Backporting to beta (#4418)

* v1.5.1

* Disable notifications (#4243)

* Fix wrong token handling (#4254)

* Fixing wrong token displayed

* Linting

* Revert filtering out

* Revert the revert

* Don't panic on uknown git commit hash (#4231)

* Additional logs for own transactions (#4278)

* Integration with zgp whitelist contract (#4215)

* zgp-transactions checker

* polishing

* rename + refactor

* refuse-service-transactions cl option

* fixed tests compilation

* Renaming signAndSendTransaction to sendTransaction (#4351)

* Fixed deadlock in external_url (#4354)

* Fixing web3 in console (#4382)

* Fixing estimate gas in case histogram is not available (#4387)

* Restarting fetch client every now and then (#4399)
This commit is contained in:
Arkadiy Paronyan 2017-02-03 13:57:04 +01:00 committed by Gav Wood
parent b09cfe1885
commit c7dbd87f8e
40 changed files with 1501 additions and 734 deletions

134
Cargo.lock generated
View File

@ -1,6 +1,6 @@
[root]
name = "parity"
version = "1.5.0"
version = "1.5.1"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -23,7 +23,7 @@ dependencies = [
"ethcore-rpc 1.5.0",
"ethcore-signer 1.5.0",
"ethcore-stratum 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethsync 1.5.0",
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -72,6 +72,11 @@ name = "ansi_term"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "antidote"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "app_dirs"
version = "1.1.1"
@ -292,6 +297,11 @@ name = "dtoa"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dtoa"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "elastic-array"
version = "0.6.0"
@ -362,7 +372,7 @@ dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-ipc-nano 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethjson 0.1.0",
"ethkey 0.2.0",
"ethstore 0.1.0",
@ -410,7 +420,7 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.5.0",
"ethcore-rpc 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"fetch 0.1.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
@ -458,7 +468,7 @@ name = "ethcore-ipc"
version = "1.5.0"
dependencies = [
"ethcore-devtools 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -505,7 +515,7 @@ dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-ipc-nano 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -520,7 +530,7 @@ dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-network 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.1.0",
"smallvec 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -532,7 +542,7 @@ name = "ethcore-logger"
version = "1.5.0"
dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -548,7 +558,7 @@ dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-devtools 1.5.0",
"ethcore-io 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethcrypto 0.1.0",
"ethkey 0.2.0",
"igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -575,7 +585,7 @@ dependencies = [
"ethcore-devtools 1.5.0",
"ethcore-io 1.5.0",
"ethcore-ipc 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethcrypto 0.1.0",
"ethjson 0.1.0",
"ethkey 0.2.0",
@ -610,7 +620,7 @@ dependencies = [
"ethcore-devtools 1.5.0",
"ethcore-io 1.5.0",
"ethcore-rpc 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -629,7 +639,7 @@ dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-ipc-nano 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
"jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -640,7 +650,7 @@ dependencies = [
[[package]]
name = "ethcore-util"
version = "1.5.0"
version = "1.5.1"
dependencies = [
"ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
@ -689,7 +699,7 @@ dependencies = [
name = "ethjson"
version = "0.1.0"
dependencies = [
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -745,7 +755,7 @@ dependencies = [
"ethcore-ipc-nano 1.5.0",
"ethcore-light 1.5.0",
"ethcore-network 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethkey 0.2.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -779,7 +789,8 @@ dependencies = [
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -896,6 +907,35 @@ dependencies = [
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hyper"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hyper-native-tls"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "idna"
version = "0.1.0"
@ -924,7 +964,7 @@ version = "1.5.0"
dependencies = [
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -949,6 +989,11 @@ name = "itoa"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jsonrpc-core"
version = "4.0.0"
@ -1444,7 +1489,7 @@ name = "parity-hash-fetch"
version = "1.5.0"
dependencies = [
"ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"fetch 0.1.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1469,7 +1514,7 @@ version = "1.4.0"
dependencies = [
"ethcore-rpc 1.5.0",
"ethcore-signer 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1515,7 +1560,7 @@ dependencies = [
"ethcore 1.5.0",
"ethcore-ipc 1.5.0",
"ethcore-ipc-codegen 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"ethsync 1.5.0",
"ipc-common-types 1.5.0",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1715,15 +1760,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "reqwest"
version = "0.2.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -1795,7 +1840,7 @@ version = "1.4.0"
dependencies = [
"ethcore-bigint 0.1.2",
"ethcore-rpc 1.5.0",
"ethcore-util 1.5.0",
"ethcore-util 1.5.1",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-rpc-client 1.4.0",
"rpassword 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1909,6 +1954,11 @@ name = "serde"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_codegen"
version = "0.8.4"
@ -1943,11 +1993,24 @@ dependencies = [
]
[[package]]
name = "serde_urlencoded"
version = "0.3.0"
name = "serde_json"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
"dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_urlencoded"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2364,6 +2427,7 @@ dependencies = [
"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
"checksum aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67077478f0a03952bed2e6786338d400d40c25e9836e08ad50af96607317fd03"
"checksum ansi_term 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1f46cd5b1d660c938e3f92dfe7a73d832b3281479363dd0cd9c1c2fbf60f7962"
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
"checksum arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "16e3bdb2f54b3ace0285975d59a97cf8ed3855294b2b6bc651fcf22a9c352975"
"checksum aster 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07d344974f0a155f091948aa389fb1b912d3a58414fbdb9c8d446d193ee3496a"
@ -2393,6 +2457,7 @@ dependencies = [
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
"checksum docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc0acb4ce0828c6a5a11d47baa432fe885881c27428c3a4e473e454ffe57a76"
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
"checksum dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f"
"checksum elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)" = "<none>"
"checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5"
"checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
@ -2409,12 +2474,15 @@ dependencies = [
"checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58"
"checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae"
"checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "<none>"
"checksum hyper 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "220407e5a263f110ec30a071787c9535918fdfc97def5680c90013c3f30c38c1"
"checksum hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb3fc65554155980167fb821d05c7c66177f92464976c0b676a19d9e03387a7"
"checksum hyper-native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afe68f772f0497a7205e751626bb8e1718568b58534b6108c73a74ef80483409"
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
"checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484"
"checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c"
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
"checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5"
"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
"checksum jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git?branch=mio-old)" = "<none>"
@ -2490,7 +2558,7 @@ dependencies = [
"checksum rayon 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "655df67c314c30fa3055a365eae276eb88aa4f3413a352a1ab32c1320eda41ea"
"checksum regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)" = "b4329b8928a284580a1c63ec9d846b12f6d3472317243ff7077aff11f23f2b29"
"checksum regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "841591b1e05609a643e3b4d0045fce04f701daba7151ddcd3ad47b080693d5a9"
"checksum reqwest 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83186fee0d4dbeb95e610b77b05b05cf5b31703dd375222acb74c3dff4be957c"
"checksum reqwest 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bef9ed8fdfcc30947d6b774938dc0c3f369a474efe440df2c7f278180b2d2e6"
"checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
@ -2509,10 +2577,12 @@ dependencies = [
"checksum semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2ff60ecdb19c255841c066cbfa5f8c2a4ada1eb3ae47c77ab6667128da71f5"
"checksum semver-parser 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e88e43a5a74dd2a11707f9c21dfd4a423c66bd871df813227bb0a3e78f3a1ae9"
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5"
"checksum serde 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4d8f810025e9d09c4eaa49c16eaf878f34a947889e878cd7d3b5bef3197cc119"
"checksum serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e422ae53d7933f59c6ff57e7b5870b5c9094b1f473f78ec33d89f8a692c3ec02"
"checksum serde_codegen_internals 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f877e2781ed0a323295d1c9f0e26556117b5a11489fc47b1848dfb98b3173d21"
"checksum serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e10f8a9d94b06cf5d3bef66475f04c8ff90950f1be7004c357ff9472ccbaebc"
"checksum serde_urlencoded 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53d4ebaa8d1d4f90d1b63dfca81ccd98ac20e1e479dbae393cbaf60f6fecd8d8"
"checksum serde_json 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fea48f4d4df4e620e3c81fd2bf28c93dd0d266361a76bac4f254b71f0e13f3cd"
"checksum serde_urlencoded 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a81f15da4b9780e1524697f73b09076b6e42298ef673bead9ca8f848b334ef84"
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
"checksum siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c44e42fa187b5a8782489cf7740cc27c3125806be2bf33563cf5e02e9533fcd"

View File

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

View File

@ -300,22 +300,29 @@ impl TestBlockChainClient {
}
}
/// Inserts a transaction to miners transactions queue.
pub fn insert_transaction_to_queue(&self) {
/// Inserts a transaction with given gas price to miners transactions queue.
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
let keypair = Random.generate().unwrap();
let tx = Transaction {
action: Action::Create,
value: U256::from(100),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::from(20_000_000_000u64),
gas_price: gas_price,
nonce: U256::zero()
};
let signed_tx = tx.sign(keypair.secret(), None);
self.set_balance(signed_tx.sender().unwrap(), 10_000_000_000_000_000_000u64.into());
let res = self.miner.import_external_transactions(self, vec![signed_tx]);
let hash = signed_tx.hash();
let res = self.miner.import_external_transactions(self, vec![signed_tx.into()]);
let res = res.into_iter().next().unwrap().expect("Successful import");
assert_eq!(res, TransactionImportResult::Current);
hash
}
/// Inserts a transaction to miners transactions queue.
pub fn insert_transaction_to_queue(&self) -> H256 {
self.insert_transaction_with_gas_price_to_queue(U256::from(20_000_000_000u64))
}
/// Set reported history size.

View File

@ -37,7 +37,6 @@ use bit_set::BitSet;
use util::*;
type CodePosition = usize;
type ProgramCounter = usize;
const ONE: U256 = U256([1, 0, 0, 0]);

View File

@ -22,7 +22,7 @@ use std::ops::{Deref, DerefMut};
use std::cell::Cell;
use transaction::{SignedTransaction, Action};
use transient_hashmap::TransientHashMap;
use miner::{TransactionQueue, TransactionImportResult, TransactionOrigin, AccountDetails};
use miner::{TransactionQueue, TransactionQueueDetailsProvider, TransactionImportResult, TransactionOrigin};
use miner::transaction_queue::QueuingInstant;
use error::{Error, TransactionError};
use util::{Uint, U256, H256, Address, Hashable};
@ -76,16 +76,12 @@ impl BanningTransactionQueue {
/// Add to the queue taking bans into consideration.
/// May reject transaction because of the banlist.
pub fn add_with_banlist<F, G>(
pub fn add_with_banlist(
&mut self,
transaction: SignedTransaction,
time: QueuingInstant,
account_details: &F,
gas_estimator: &G,
) -> Result<TransactionImportResult, Error> where
F: Fn(&Address) -> AccountDetails,
G: Fn(&SignedTransaction) -> U256,
{
details_provider: &TransactionQueueDetailsProvider,
) -> Result<TransactionImportResult, Error> {
if let Threshold::BanAfter(threshold) = self.ban_threshold {
// NOTE In all checks use direct query to avoid increasing ban timeout.
@ -117,7 +113,7 @@ impl BanningTransactionQueue {
}
}
}
self.queue.add(transaction, TransactionOrigin::External, time, None, account_details, gas_estimator)
self.queue.add(transaction, TransactionOrigin::External, time, None, details_provider)
}
/// Ban transaction with given hash.
@ -220,22 +216,16 @@ mod tests {
use transaction::{Transaction, SignedTransaction, Action};
use error::{Error, TransactionError};
use client::TransactionImportResult;
use miner::{TransactionQueue, TransactionOrigin, AccountDetails};
use miner::{TransactionQueue, TransactionOrigin};
use util::{Uint, U256, Address, FromHex, Hashable};
use miner::transaction_queue::test::DummyTransactionDetailsProvider;
fn queue() -> BanningTransactionQueue {
BanningTransactionQueue::new(TransactionQueue::default(), Threshold::BanAfter(1), Duration::from_secs(180))
}
fn default_account_details(_address: &Address) -> AccountDetails {
AccountDetails {
nonce: U256::zero(),
balance: !U256::zero(),
}
}
fn gas_required(_tx: &SignedTransaction) -> U256 {
0.into()
fn default_tx_provider() -> DummyTransactionDetailsProvider {
DummyTransactionDetailsProvider::default().with_account_nonce(U256::zero())
}
fn transaction(action: Action) -> SignedTransaction {
@ -265,7 +255,7 @@ mod tests {
let mut txq = queue();
// when
txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_account_details, &gas_required).unwrap();
txq.queue().add(tx, TransactionOrigin::External, 0, None, &default_tx_provider()).unwrap();
// then
// should also deref to queue
@ -281,12 +271,12 @@ mod tests {
let banlist1 = txq.ban_sender(tx.sender().unwrap());
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_sender(tx.sender().unwrap());
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
// then
assert!(banlist2, "Threshold should be reached - banned.");
@ -305,12 +295,12 @@ mod tests {
let banlist1 = txq.ban_recipient(recipient);
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_recipient(recipient);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
// then
assert!(banlist2, "Threshold should be reached - banned.");
@ -327,12 +317,12 @@ mod tests {
let banlist1 = txq.ban_codehash(codehash);
assert!(!banlist1, "Threshold not reached yet.");
// Insert once
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required).unwrap();
let import1 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider()).unwrap();
assert_eq!(import1, TransactionImportResult::Current);
// when
let banlist2 = txq.ban_codehash(codehash);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_account_details, &gas_required);
let import2 = txq.add_with_banlist(tx.clone(), 0, &default_tx_provider());
// then
assert!(banlist2, "Threshold should be reached - banned.");

View File

@ -70,36 +70,43 @@ impl LocalTransactionsList {
}
pub fn mark_pending(&mut self, hash: H256) {
debug!(target: "own_tx", "Imported to Current (hash {:?})", hash);
self.clear_old();
self.transactions.insert(hash, Status::Pending);
}
pub fn mark_future(&mut self, hash: H256) {
debug!(target: "own_tx", "Imported to Future (hash {:?})", hash);
self.transactions.insert(hash, Status::Future);
self.clear_old();
}
pub fn mark_rejected(&mut self, tx: SignedTransaction, err: TransactionError) {
debug!(target: "own_tx", "Transaction rejected (hash {:?}): {:?}", tx.hash(), err);
self.transactions.insert(tx.hash(), Status::Rejected(tx, err));
self.clear_old();
}
pub fn mark_replaced(&mut self, tx: SignedTransaction, gas_price: U256, hash: H256) {
debug!(target: "own_tx", "Transaction replaced (hash {:?}) by {:?} (new gas price: {:?})", tx.hash(), hash, gas_price);
self.transactions.insert(tx.hash(), Status::Replaced(tx, gas_price, hash));
self.clear_old();
}
pub fn mark_invalid(&mut self, tx: SignedTransaction) {
warn!(target: "own_tx", "Transaction marked invalid (hash {:?})", tx.hash());
self.transactions.insert(tx.hash(), Status::Invalid(tx));
self.clear_old();
}
pub fn mark_dropped(&mut self, tx: SignedTransaction) {
warn!(target: "own_tx", "Transaction dropped (hash {:?})", tx.hash());
self.transactions.insert(tx.hash(), Status::Dropped(tx));
self.clear_old();
}
pub fn mark_mined(&mut self, tx: SignedTransaction) {
info!(target: "own_tx", "Transaction mined (hash {:?})", tx.hash());
self.transactions.insert(tx.hash(), Status::Mined(tx));
self.clear_old();
}

View File

@ -30,11 +30,13 @@ use transaction::{Action, SignedTransaction, PendingTransaction};
use receipt::{Receipt, RichReceipt};
use spec::Spec;
use engines::{Engine, Seal};
use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
use miner::{MinerService, MinerStatus, TransactionQueue, TransactionQueueDetailsProvider, PrioritizationStrategy,
AccountDetails, TransactionOrigin};
use miner::banning_queue::{BanningTransactionQueue, Threshold};
use miner::work_notify::WorkPoster;
use miner::price_info::PriceInfo;
use miner::local_transactions::{Status as LocalTransactionStatus};
use miner::service_transaction_checker::ServiceTransactionChecker;
use header::BlockNumber;
/// Different possible definitions for pending transaction set.
@ -103,8 +105,10 @@ pub struct MinerOptions {
pub enable_resubmission: bool,
/// Global gas limit for all transaction in the queue except for local and retracted.
pub tx_queue_gas_limit: GasLimit,
/// Banning settings
/// Banning settings.
pub tx_queue_banning: Banning,
/// Do we refuse to accept service transactions even if sender is certified.
pub refuse_service_transactions: bool,
}
impl Default for MinerOptions {
@ -123,6 +127,7 @@ impl Default for MinerOptions {
work_queue_size: 20,
enable_resubmission: true,
tx_queue_banning: Banning::Disabled,
refuse_service_transactions: false,
}
}
}
@ -222,6 +227,7 @@ pub struct Miner {
accounts: Option<Arc<AccountProvider>>,
work_poster: Option<WorkPoster>,
gas_pricer: Mutex<GasPricer>,
service_transaction_action: ServiceTransactionAction,
}
impl Miner {
@ -245,6 +251,10 @@ impl Miner {
ban_duration,
),
};
let service_transaction_action = match options.refuse_service_transactions {
true => ServiceTransactionAction::Refuse,
false => ServiceTransactionAction::Check(ServiceTransactionChecker::default()),
};
Miner {
transaction_queue: Arc::new(Mutex::new(txq)),
next_allowed_reseal: Mutex::new(Instant::now()),
@ -264,6 +274,7 @@ impl Miner {
engine: spec.engine.clone(),
work_poster: work_poster,
gas_pricer: Mutex::new(gas_pricer),
service_transaction_action: service_transaction_action,
}
}
@ -527,8 +538,8 @@ impl Miner {
}
}
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {
let gas_limit = chain.best_block_header().gas_limit();
fn update_gas_limit(&self, client: &MiningBlockChainClient) {
let gas_limit = client.best_block_header().gas_limit();
let mut queue = self.transaction_queue.lock();
queue.set_gas_limit(gas_limit);
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
@ -538,7 +549,7 @@ impl Miner {
}
/// Returns true if we had to prepare new pending block.
fn prepare_work_sealing(&self, chain: &MiningBlockChainClient) -> bool {
fn prepare_work_sealing(&self, client: &MiningBlockChainClient) -> bool {
trace!(target: "miner", "prepare_work_sealing: entering");
let prepare_new = {
let mut sealing_work = self.sealing_work.lock();
@ -556,11 +567,11 @@ impl Miner {
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
let (block, original_work_hash) = self.prepare_block(chain);
let (block, original_work_hash) = self.prepare_block(client);
self.prepare_work(block, original_work_hash);
}
let mut sealing_block_last_request = self.sealing_block_last_request.lock();
let best_number = chain.chain_info().best_block_number;
let best_number = client.chain_info().best_block_number;
if *sealing_block_last_request != best_number {
trace!(target: "miner", "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number);
*sealing_block_last_request = best_number;
@ -572,39 +583,25 @@ impl Miner {
fn add_transactions_to_queue(
&self,
chain: &MiningBlockChainClient,
client: &MiningBlockChainClient,
transactions: Vec<SignedTransaction>,
default_origin: TransactionOrigin,
min_block: Option<BlockNumber>,
transaction_queue: &mut BanningTransactionQueue)
-> Vec<Result<TransactionImportResult, Error>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: chain.latest_nonce(a),
balance: chain.latest_balance(a),
};
transaction_queue: &mut BanningTransactionQueue,
) -> Vec<Result<TransactionImportResult, Error>> {
let accounts = self.accounts.as_ref()
.and_then(|provider| provider.accounts().ok())
.map(|accounts| accounts.into_iter().collect::<HashSet<_>>());
let schedule = chain.latest_schedule();
let gas_required = |tx: &SignedTransaction| tx.gas_required(&schedule).into();
let best_block_header = chain.best_block_header().decode();
let insertion_time = chain.chain_info().best_block_number;
let insertion_time = client.chain_info().best_block_number;
transactions.into_iter()
.map(|tx| {
if chain.transaction_block(TransactionId::Hash(tx.hash())).is_some() {
debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", tx.hash());
let hash = tx.hash();
if client.transaction_block(TransactionId::Hash(hash)).is_some() {
debug!(target: "miner", "Rejected tx {:?}: already in the blockchain", hash);
return Err(Error::Transaction(TransactionError::AlreadyImported));
}
match self.engine.verify_transaction_basic(&tx, &best_block_header) {
Err(e) => {
debug!(target: "miner", "Rejected tx {:?} with invalid signature: {:?}", tx.hash(), e);
Err(e)
},
Ok(()) => {
let origin = accounts.as_ref().and_then(|accounts| {
tx.sender().ok().and_then(|sender| match accounts.contains(&sender) {
true => Some(TransactionOrigin::Local),
@ -612,14 +609,16 @@ impl Miner {
})
}).unwrap_or(default_origin);
// try to install service transaction checker before appending transactions
self.service_transaction_action.update_from_chain_client(client);
let details_provider = TransactionDetailsProvider::new(client, &self.service_transaction_action);
match origin {
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
transaction_queue.add(tx, origin, insertion_time, min_block, &fetch_account, &gas_required)
transaction_queue.add(tx, origin, insertion_time, min_block, &details_provider)
},
TransactionOrigin::External => {
transaction_queue.add_with_banlist(tx, insertion_time, &fetch_account, &gas_required)
}
}
transaction_queue.add_with_banlist(tx, insertion_time, &details_provider)
},
}
})
@ -867,7 +866,6 @@ impl MinerService for Miner {
pending: PendingTransaction,
) -> Result<TransactionImportResult, Error> {
let hash = pending.transaction.hash();
trace!(target: "own_tx", "Importing transaction: {:?}", pending);
let imported = {
@ -878,12 +876,10 @@ impl MinerService for Miner {
).pop().expect("one result returned per added transaction; one added => one result; qed");
match import {
Ok(ref res) => {
trace!(target: "own_tx", "Imported transaction to {:?} (hash: {:?})", res, hash);
Ok(_) => {
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
},
Err(ref e) => {
trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash);
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
warn!(target: "own_tx", "Error importing transaction: {:?}", e);
},
@ -1165,6 +1161,60 @@ impl MinerService for Miner {
}
}
/// Action when service transaction is received
enum ServiceTransactionAction {
/// Refuse service transaction immediately
Refuse,
/// Accept if sender is certified to send service transactions
Check(ServiceTransactionChecker),
}
impl ServiceTransactionAction {
pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) {
if let ServiceTransactionAction::Check(ref checker) = *self {
checker.update_from_chain_client(client);
}
}
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
match *self {
ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()),
ServiceTransactionAction::Check(ref checker) => checker.check(client, tx),
}
}
}
struct TransactionDetailsProvider<'a> {
client: &'a MiningBlockChainClient,
service_transaction_action: &'a ServiceTransactionAction,
}
impl<'a> TransactionDetailsProvider<'a> {
pub fn new(client: &'a MiningBlockChainClient, service_transaction_action: &'a ServiceTransactionAction) -> Self {
TransactionDetailsProvider {
client: client,
service_transaction_action: service_transaction_action,
}
}
}
impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> {
fn fetch_account(&self, address: &Address) -> AccountDetails {
AccountDetails {
nonce: self.client.latest_nonce(address),
balance: self.client.latest_balance(address),
}
}
fn estimate_gas_required(&self, tx: &SignedTransaction) -> U256 {
tx.gas_required(&self.client.latest_schedule()).into()
}
fn is_service_transaction_acceptable(&self, tx: &SignedTransaction) -> Result<bool, String> {
self.service_transaction_action.check(self.client, tx)
}
}
#[cfg(test)]
mod tests {
@ -1229,6 +1279,7 @@ mod tests {
work_queue_size: 5,
enable_resubmission: true,
tx_queue_banning: Banning::Disabled,
refuse_service_transactions: false,
},
GasPricer::new_fixed(0u64.into()),
&Spec::new_test(),

View File

@ -46,12 +46,14 @@ mod external;
mod local_transactions;
mod miner;
mod price_info;
mod service_transaction_checker;
mod transaction_queue;
mod work_notify;
pub use self::external::{ExternalMiner, ExternalMinerService};
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
pub use self::transaction_queue::{TransactionQueue, TransactionDetailsProvider as TransactionQueueDetailsProvider,
PrioritizationStrategy, AccountDetails, TransactionOrigin};
pub use self::local_transactions::{Status as LocalTransactionStatus};
pub use client::TransactionImportResult;

View File

@ -0,0 +1,212 @@
// Copyright 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 client::MiningBlockChainClient;
use transaction::SignedTransaction;
use util::{U256, Uint, Mutex};
const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker";
/// Service transactions checker.
#[derive(Default)]
pub struct ServiceTransactionChecker {
contract: Mutex<Option<provider::Contract>>,
}
impl ServiceTransactionChecker {
/// Try to create instance, reading contract address from given chain client.
pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) {
let mut contract = self.contract.lock();
if contract.is_none() {
*contract = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned())
.and_then(|contract_addr| {
trace!(target: "txqueue", "Configuring for service transaction checker contract from {}", contract_addr);
Some(provider::Contract::new(contract_addr))
})
}
}
/// Checks if service transaction can be appended to the transaction queue.
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
debug_assert_eq!(tx.gas_price, U256::zero());
if let Some(ref contract) = *self.contract.lock() {
let do_call = |a, d| client.call_contract(a, d);
contract.certified(&do_call, &tx.sender().unwrap())
} else {
Err("contract is not configured".to_owned())
}
}
}
mod provider {
// Autogenerated from JSON contract definition using Rust contract convertor.
// Command line: --jsonabi=SimpleCertifier.abi --explicit-do-call
#![allow(unused_imports)]
use std::string::String;
use std::result::Result;
use std::fmt;
use {util, ethabi};
use util::{FixedHash, Uint};
pub struct Contract {
contract: ethabi::Contract,
address: util::Address,
}
impl Contract {
pub fn new(address: util::Address) -> Self
{
Contract {
contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certify\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getAddress\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"revoke\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"delegate\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"getUint\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_new\",\"type\":\"address\"}],\"name\":\"setDelegate\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"}],\"name\":\"certified\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_who\",\"type\":\"address\"},{\"name\":\"_field\",\"type\":\"string\"}],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")),
address: address,
}
}
fn as_string<T: fmt::Debug>(e: T) -> String { format!("{:?}", e) }
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn set_owner<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("setOwner".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_new.clone().0)]
).map_err(Self::as_string)?;
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
Ok(())
}
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn certify<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("certify".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0)]
).map_err(Self::as_string)?;
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
Ok(())
}
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn get_address<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("getAddress".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
}
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn revoke<F>(&self, do_call: &F, _who: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("revoke".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0)]
).map_err(Self::as_string)?;
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
Ok(())
}
/// Auto-generated from: `{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn owner<F>(&self, do_call: &F) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("owner".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
}
/// Auto-generated from: `{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn delegate<F>(&self, do_call: &F) -> Result<util::Address, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("delegate".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_address().ok_or("Invalid type returned")?; util::Address::from(r) }))
}
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn get_uint<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::U256, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("getUint".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_uint().ok_or("Invalid type returned")?; util::U256::from(r.as_ref()) }))
}
/// Auto-generated from: `{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn set_delegate<F>(&self, do_call: &F, _new: &util::Address) -> Result<(), String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("setDelegate".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_new.clone().0)]
).map_err(Self::as_string)?;
call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
Ok(())
}
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn certified<F>(&self, do_call: &F, _who: &util::Address) -> Result<bool, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("certified".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0)]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_bool().ok_or("Invalid type returned")?; r }))
}
/// Auto-generated from: `{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}`
#[allow(dead_code)]
pub fn get<F>(&self, do_call: &F, _who: &util::Address, _field: &str) -> Result<util::H256, String>
where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send {
let call = self.contract.function("get".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![ethabi::Token::Address(_who.clone().0), ethabi::Token::String(_field.to_owned())]
).map_err(Self::as_string)?;
let output = call.decode_output((do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
let mut result = output.into_iter().rev().collect::<Vec<_>>();
Ok(({ let r = result.pop().ok_or("Invalid return arity")?; let r = r.to_fixed_bytes().ok_or("Invalid type returned")?; util::H256::from_slice(r.as_ref()) }))
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -17,8 +17,9 @@
//! Types used in the public API
use std::fmt;
use std::str::FromStr;
use semver::{Version};
use util::{H160};
use util::{H160, FixedHash};
use util::misc::raw_package_info;
use release_track::ReleaseTrack;
@ -47,7 +48,7 @@ impl VersionInfo {
VersionInfo {
track: raw.0.into(),
version: { let mut v = Version::parse(raw.1).expect("Environment variables are known to be valid; qed"); v.build = vec![]; v.pre = vec![]; v },
hash: raw.2.into(),
hash: H160::from_str(raw.2).unwrap_or_else(|_| H160::zero()),
}
}

View File

@ -34,9 +34,9 @@ export default class Personal {
.then(outAddress);
}
signAndSendTransaction (options, password) {
sendTransaction (options, password) {
return this._transport
.execute('personal_signAndSendTransaction', inOptions(options), password);
.execute('personal_sendTransaction', inOptions(options), password);
}
unlockAccount (account, password, duration = 1) {

View File

@ -4,8 +4,7 @@
<meta charset="utf-8">
<title>JS Console dapp</title>
<link href="console.css" rel='stylesheet' type='text/css'>
<script src="/parity-utils/parity.js"></script>
<script src="/parity-utils/web3.js"></script>
<script src="/web3.js"></script>
</head>
<body>
<div id="full-screen">

View File

@ -40,8 +40,8 @@ export default {
}
},
signAndSendTransaction: {
desc: 'Sends and signs a transaction given account passphrase. Does not require the account to be unlocked nor unlocks the account for future transactions. ',
sendTransaction: {
desc: 'Sends transaction and signs it in a single call. The account does not need to be unlocked to make this call, and will not be left unlocked after.',
params: [
{
type: Object,

View File

@ -96,7 +96,7 @@ class TokenSelect extends Component {
return (
<MenuItem
key={ token.tag }
key={ `${index}_${token.tag}` }
value={ token.tag }
label={ label }>
{ label }

View File

@ -31,7 +31,8 @@ const log = getLogger(LOG_KEYS.Balances);
const ETH = {
name: 'Ethereum',
tag: 'ETH',
image: imagesEthereum
image: imagesEthereum,
native: true
};
function setBalances (_balances, skipNotifications = false) {
@ -39,10 +40,9 @@ function setBalances (_balances, skipNotifications = false) {
const state = getState();
const currentTokens = Object.values(state.balances.tokens || {});
const currentTags = [ 'eth' ]
.concat(currentTokens.map((token) => token.tag))
.filter((tag) => tag)
.map((tag) => tag.toLowerCase());
const tokensAddresses = currentTokens
.map((token) => token.address)
.filter((address) => address);
const accounts = state.personal.accounts;
const nextBalances = _balances;
@ -61,11 +61,7 @@ function setBalances (_balances, skipNotifications = false) {
const prevTokens = balance.tokens.slice();
const nextTokens = [];
currentTags
.forEach((tag) => {
const prevToken = prevTokens.find((tok) => tok.token.tag.toLowerCase() === tag);
const nextToken = tokens.find((tok) => tok.token.tag.toLowerCase() === tag);
const handleToken = (prevToken, nextToken) => {
// If the given token is not in the current tokens, skip
if (!nextToken && !prevToken) {
return false;
@ -105,6 +101,19 @@ function setBalances (_balances, skipNotifications = false) {
...prevToken,
value
});
};
const prevEthToken = prevTokens.find((tok) => tok.token.native);
const nextEthToken = tokens.find((tok) => tok.token.native);
handleToken(prevEthToken, nextEthToken);
tokensAddresses
.forEach((address) => {
const prevToken = prevTokens.find((tok) => tok.token.address === address);
const nextToken = tokens.find((tok) => tok.token.address === address);
handleToken(prevToken, nextToken);
});
balances[address] = { txCount: txCount || new BigNumber(0), tokens: nextTokens };
@ -176,6 +185,8 @@ export function fetchTokens (_tokenIds, options = {}) {
return Promise
.all(tokenIds.map((id) => fetchTokenInfo(tokenreg, id, api)))
// FIXME ; shouldn't have to filter out tokens...
.then((tokens) => tokens.filter((token) => token.tag && token.tag.toLowerCase() !== 'eth'))
.then((tokens) => {
// dispatch only the changed images
tokens

View File

@ -41,7 +41,7 @@ class Balance extends Component {
let body = (balance.tokens || [])
.filter((balance) => new BigNumber(balance.value).gt(0))
.map((balance) => {
.map((balance, index) => {
const token = balance.token;
let value;
@ -76,7 +76,8 @@ class Balance extends Component {
return (
<div
className={ styles.balance }
key={ token.tag }>
key={ `${index}_${token.tag}` }
>
<img
src={ imagesrc }
alt={ token.name } />

View File

@ -124,7 +124,12 @@ export default class GasPriceEditor {
@action loadDefaults () {
Promise
.all([
this._api.parity.gasPriceHistogram(),
// NOTE fetching histogram may fail if there is not enough data.
// We fallback to empty histogram.
this._api.parity.gasPriceHistogram().catch(() => ({
bucket_bounds: [],
counts: []
})),
this._api.eth.gasPrice()
])
.then(([histogram, _price]) => {

View File

@ -62,6 +62,31 @@ describe('ui/GasPriceEditor/store', () => {
});
});
describe('constructor (defaults) when histogram not available', () => {
const api = {
eth: {
gasPrice: sinon.stub().resolves(GASPRICE)
},
parity: {
gasPriceHistogram: sinon.stub().rejects('Data not available')
}
};
beforeEach(() => {
store = new Store(api, { gasLimit: GASLIMIT });
});
it('retrieves the histogram and gasPrice', done => {
expect(api.eth.gasPrice).to.have.been.called;
expect(api.parity.gasPriceHistogram).to.have.been.called;
setImmediate(() => {
expect(store.histogram).not.to.be.null;
done();
});
});
});
describe('setters', () => {
beforeEach(() => {
store = new Store(null, { gasLimit: GASLIMIT });

View File

@ -21,8 +21,8 @@ export default function web3extensions (web3) {
property: 'personal',
methods: [
new Method({
name: 'signAndSendTransaction',
call: 'personal_signAndSendTransaction',
name: 'sendTransaction',
call: 'personal_sendTransaction',
params: 2,
inputFormatter: [formatters.inputTransactionFormatter, null]
}),

View File

@ -829,7 +829,7 @@
"outputFormatter": null
},
{
"name": "personal_signAndSendTransaction",
"name": "personal_sendTransaction",
"desc": "Sends and signs a transaction given account passphrase. Does not require the account to be unlocked nor unlocks the account for future transactions. ",
"params": [
{

View File

@ -578,7 +578,7 @@
<key>OVERWRITE_PERMISSIONS</key>
<false/>
<key>VERSION</key>
<string>1.5.0</string>
<string>1.5.1</string>
</dict>
<key>UUID</key>
<string>2DCD5B81-7BAF-4DA1-9251-6274B089FD36</string>

View File

@ -10,7 +10,7 @@
!define DESCRIPTION "Fast, light, robust Ethereum implementation"
!define VERSIONMAJOR 1
!define VERSIONMINOR 5
!define VERSIONBUILD 0
!define VERSIONBUILD 1
!define ARGS "--warp"
!define FIRST_START_ARGS "ui --warp --mode=passive"

View File

@ -90,6 +90,7 @@ tx_time_limit = 100 #ms
extra_data = "Parity"
remove_solved = false
notify_work = ["http://localhost:3001"]
refuse_service_transactions = false
[footprint]
tracing = "auto"

View File

@ -230,6 +230,8 @@ usage! {
or |c: &Config| otry!(c.mining).remove_solved.clone(),
flag_notify_work: Option<String> = None,
or |c: &Config| otry!(c.mining).notify_work.clone().map(|vec| Some(vec.join(","))),
flag_refuse_service_transactions: bool = false,
or |c: &Config| otry!(c.mining).refuse_service_transactions.clone(),
// -- Footprint Options
flag_tracing: String = "auto",
@ -414,6 +416,7 @@ struct Mining {
tx_queue_ban_time: Option<u16>,
remove_solved: Option<bool>,
notify_work: Option<Vec<String>>,
refuse_service_transactions: Option<bool>,
}
#[derive(Default, Debug, PartialEq, RustcDecodable)]
@ -630,6 +633,7 @@ mod tests {
flag_tx_queue_ban_time: 180u16,
flag_remove_solved: false,
flag_notify_work: Some("http://localhost:3001".into()),
flag_refuse_service_transactions: false,
// -- Footprint Options
flag_tracing: "auto".into(),
@ -807,6 +811,7 @@ mod tests {
extra_data: None,
remove_solved: None,
notify_work: None,
refuse_service_transactions: None,
}),
footprint: Some(Footprint {
tracing: Some("on".into()),

View File

@ -258,6 +258,8 @@ Sealing/Mining Options:
--notify-work URLS URLs to which work package notifications are pushed.
URLS should be a comma-delimited list of HTTP URLs.
(default: {flag_notify_work:?})
--refuse-service-transactions Always refuse service transactions.
(default: {flag_refuse_service_transactions}).
Footprint Options:
--tracing BOOL Indicates if full transaction tracing should be
@ -271,7 +273,7 @@ Footprint Options:
fast - maintain journal overlay. Fast but 50MB used.
auto - use the method most recently synced or
default to fast if none synced (default: {flag_pruning}).
--pruning-history NUM Set a number of recent states to keep when pruning
--pruning-history NUM Set a minimum number of recent states to keep when pruning
is active. (default: {flag_pruning_history}).
--cache-size-db MB Override database cache size (default: {flag_cache_size_db}).
--cache-size-blocks MB Specify the prefered size of the blockchain cache in

View File

@ -485,7 +485,8 @@ impl Configuration {
ban_duration: Duration::from_secs(self.args.flag_tx_queue_ban_time as u64),
},
None => Banning::Disabled,
}
},
refuse_service_transactions: self.args.flag_refuse_service_transactions,
};
Ok(options)

View File

@ -54,9 +54,6 @@ pub enum QueueAddError {
LimitReached,
}
/// Message Receiver type
pub type QueueEventReceiver = mpsc::Receiver<QueueEvent>;
// TODO [todr] to consider: timeout instead of limit?
const QUEUE_LIMIT: usize = 50;

View File

@ -102,7 +102,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
}
}
fn sign_and_send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
fn send_transaction(&self, request: TransactionRequest, password: String) -> Result<RpcH256, Error> {
self.active()?;
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);

View File

@ -66,6 +66,7 @@ fn miner_service(spec: &Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
reseal_min_period: Duration::from_secs(0),
work_queue_size: 50,
enable_resubmission: true,
refuse_service_transactions: false,
},
GasPricer::new_fixed(20_000_000_000u64.into()),
&spec,

View File

@ -96,7 +96,7 @@ fn sign_and_send_transaction_with_invalid_password() {
let address = tester.accounts.new_account("password123").unwrap();
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_signAndSendTransaction",
"method": "personal_sendTransaction",
"params": [{
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
@ -119,7 +119,7 @@ fn sign_and_send_transaction() {
let request = r#"{
"jsonrpc": "2.0",
"method": "personal_signAndSendTransaction",
"method": "personal_sendTransaction",
"params": [{
"from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",

View File

@ -36,7 +36,7 @@ build_rpc_trait! {
fn unlock_account(&self, H160, String, Option<U128>) -> Result<bool, Error>;
/// Sends transaction and signs it in single call. The account is not unlocked in such case.
#[rpc(name = "personal_signAndSendTransaction")]
fn sign_and_send_transaction(&self, TransactionRequest, String) -> Result<H256, Error>;
#[rpc(name = "personal_sendTransaction")]
fn send_transaction(&self, TransactionRequest, String) -> Result<H256, Error>;
}
}

View File

@ -17,6 +17,8 @@
// Rust/Parity ABI struct autogenerator.
// By Gav Wood, 2016.
var fs = require('fs');
String.prototype.replaceAll = function(f, t) { return this.split(f).join(t); }
String.prototype.toSnake = function(){
return this.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
@ -24,6 +26,7 @@ String.prototype.toSnake = function(){
function makeContractFile(name, json, prefs) {
return `// Autogenerated from JSON contract definition using Rust contract convertor.
// Command line: ${process.argv.slice(2).join(' ')}
#![allow(unused_imports)]
use std::string::String;
use std::result::Result;
@ -39,14 +42,15 @@ function convertContract(name, json, prefs) {
return `${prefs._pub ? "pub " : ""}struct ${name} {
contract: ethabi::Contract,
address: util::Address,
do_call: Box<Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send ${prefs._sync ? "+ Sync " : ""}+ 'static>,
${prefs._explicit_do_call ? "" : `do_call: Box<Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send${prefs._sync ? " + Sync " : ""}+ 'static>,`}
}
impl ${name} {
pub fn new<F>(address: util::Address, do_call: F) -> Self where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send ${prefs._sync ? "+ Sync " : ""}+ 'static {
pub fn new${prefs._explicit_do_call ? "" : "<F>"}(address: util::Address${prefs._explicit_do_call ? "" : `", do_call: F"`}) -> Self
${prefs._explicit_do_call ? "" : `where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send ${prefs._sync ? "+ Sync " : ""}+ 'static`} {
${name} {
contract: ethabi::Contract::new(ethabi::Interface::load(b"${JSON.stringify(json.filter(a => a.type == 'function')).replaceAll('"', '\\"')}").expect("JSON is autogenerated; qed")),
address: address,
do_call: Box::new(do_call),
${prefs._explicit_do_call ? "" : `do_call: Box::new(do_call),`}
}
}
fn as_string<T: fmt::Debug>(e: T) -> String { format!("{:?}", e) }
@ -205,6 +209,7 @@ function tokenExtract(expr, type, _prefs) {
}
function convertFunction(json, _prefs) {
let cprefs = _prefs || {};
let prefs = (_prefs || {})[json.name] || (_prefs || {})['_'] || {};
let snakeName = json.name.toSnake();
let params = json.inputs.map((x, i) => (x.name ? x.name.toSnake() : ("_" + (i + 1))) + ": " + mapType(x.name, x.type, prefs[x.name]));
@ -212,18 +217,35 @@ function convertFunction(json, _prefs) {
return `
/// Auto-generated from: \`${JSON.stringify(json)}\`
#[allow(dead_code)]
pub fn ${snakeName}(&self${params.length > 0 ? ', ' + params.join(", ") : ''}) -> Result<${returns}, String> {
pub fn ${snakeName}${cprefs._explicit_do_call ? "<F>" : ""}(&self${cprefs._explicit_do_call ? `, do_call: &F` : ""}${params.length > 0 ? ', ' + params.join(", ") : ''}) -> Result<${returns}, String>
${cprefs._explicit_do_call ? `where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send ${prefs._sync ? "+ Sync " : ""}` : ""} {
let call = self.contract.function("${json.name}".into()).map_err(Self::as_string)?;
let data = call.encode_call(
vec![${json.inputs.map((x, i) => convertToken(x.name ? x.name.toSnake() : ("_" + (i + 1)), x.type, prefs[x.name])).join(', ')}]
).map_err(Self::as_string)?;
${json.outputs.length > 0 ? 'let output = ' : ''}call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
${json.outputs.length > 0 ? 'let output = ' : ''}call.decode_output((${cprefs._explicit_do_call ? "" : "self."}do_call)(self.address.clone(), data)?).map_err(Self::as_string)?;
${json.outputs.length > 0 ? 'let mut result = output.into_iter().rev().collect::<Vec<_>>();' : ''}
Ok((${json.outputs.map((o, i) => tokenExtract('result.pop().ok_or("Invalid return arity")?', o.type, prefs[o.name])).join(', ')}))
}`;
}
// default preferences:
let prefs = {"_pub": true, "_": {"_client": {"string": true}, "_platform": {"string": true}}, "_sync": true};
// default contract json ABI
let jsonabi = [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}];
let out = makeContractFile("Contract", jsonabi, {"_pub": true, "_": {"_client": {"string": true}, "_platform": {"string": true}}, "_sync": true});
// parse command line options
for (let i = 1; i < process.argv.length; ++i) {
let arg = process.argv[i];
if (arg.indexOf("--jsonabi") == 0) {
jsonabi = arg.slice(10);
if (fs.existsSync(jsonabi)) {
jsonabi = JSON.parse(fs.readFileSync(jsonabi).toString());
}
} else if (arg.indexOf("--explicit-do-call") == 0) {
prefs._explicit_do_call = true;
}
}
let out = makeContractFile("Contract", jsonabi, prefs);
console.log(`${out}`);

View File

@ -96,6 +96,7 @@ use ethcore::header::{BlockNumber, Header as BlockHeader};
use ethcore::client::{BlockChainClient, BlockStatus, BlockId, BlockChainInfo, BlockImportError, BlockQueueInfo};
use ethcore::error::*;
use ethcore::snapshot::{ManifestData, RestorationStatus};
use ethcore::transaction::PendingTransaction;
use sync_io::SyncIo;
use time;
use super::SyncConfig;
@ -1959,7 +1960,46 @@ impl ChainSync {
return 0;
}
let all_transactions_hashes = transactions.iter().map(|tx| tx.transaction.hash()).collect::<HashSet<H256>>();
let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions.into_iter()
.partition(|tx| !tx.transaction.gas_price.is_zero());
// usual transactions could be propagated to all peers
let mut affected_peers = HashSet::new();
if !transactions.is_empty() {
let peers = self.select_peers_for_transactions(|_| true);
affected_peers = self.propagate_transactions_to_peers(io, peers, transactions);
}
// most of times service_transactions will be empty
// => there's no need to merge packets
if !service_transactions.is_empty() {
let service_transactions_peers = self.select_peers_for_transactions(|peer_id| accepts_service_transaction(&io.peer_info(*peer_id)));
let service_transactions_affected_peers = self.propagate_transactions_to_peers(io, service_transactions_peers, service_transactions);
affected_peers.extend(&service_transactions_affected_peers);
}
affected_peers.len()
}
fn select_peers_for_transactions<F>(&self, filter: F) -> Vec<PeerId>
where F: Fn(&PeerId) -> bool {
// sqrt(x)/x scaled to max u32
let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32;
let small = self.peers.len() < MIN_PEERS_PROPAGATION;
let mut random = random::new();
self.peers.keys()
.cloned()
.filter(filter)
.filter(|_| small || random.next_u32() < fraction)
.take(MAX_PEERS_PROPAGATION)
.collect()
}
fn propagate_transactions_to_peers(&mut self, io: &mut SyncIo, peers: Vec<PeerId>, transactions: Vec<PendingTransaction>) -> HashSet<PeerId> {
let all_transactions_hashes = transactions.iter()
.map(|tx| tx.transaction.hash())
.collect::<HashSet<H256>>();
let all_transactions_rlp = {
let mut packet = RlpStream::new_list(transactions.len());
for tx in &transactions { packet.append(&tx.transaction); }
@ -1970,26 +2010,24 @@ impl ChainSync {
self.transactions_stats.retain(&all_transactions_hashes);
// sqrt(x)/x scaled to max u32
let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32;
let small = self.peers.len() < MIN_PEERS_PROPAGATION;
let block_number = io.chain().chain_info().best_block_number;
let mut random = random::new();
let lucky_peers = {
peers.into_iter()
.filter_map(|peer_id| {
let stats = &mut self.transactions_stats;
self.peers.iter_mut()
.filter(|_| small || random.next_u32() < fraction)
.take(MAX_PEERS_PROPAGATION)
.filter_map(|(peer_id, mut peer_info)| {
let peer_info = self.peers.get_mut(&peer_id)
.expect("peer_id is form peers; peers is result of select_peers_for_transactions; select_peers_for_transactions selects peers from self.peers; qed");
// Send all transactions
if peer_info.last_sent_transactions.is_empty() {
// update stats
for hash in &all_transactions_hashes {
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
stats.propagated(*hash, id, block_number);
}
peer_info.last_sent_transactions = all_transactions_hashes.clone();
return Some((*peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone()));
return Some((peer_id, all_transactions_hashes.len(), all_transactions_rlp.clone()));
}
// Get hashes of all transactions to send to this peer
@ -2007,7 +2045,7 @@ impl ChainSync {
if to_send.contains(&tx.transaction.hash()) {
packet.append(&tx.transaction);
// update stats
let id = io.peer_session_info(*peer_id).and_then(|info| info.id);
let id = io.peer_session_info(peer_id).and_then(|info| info.id);
stats.propagated(tx.transaction.hash(), id, block_number);
}
}
@ -2017,22 +2055,25 @@ impl ChainSync {
.chain(&to_send)
.cloned()
.collect();
Some((*peer_id, to_send.len(), packet.out()))
Some((peer_id, to_send.len(), packet.out()))
})
.collect::<Vec<_>>()
};
// Send RLPs
let peers = lucky_peers.len();
if peers > 0 {
let mut peers = HashSet::new();
if lucky_peers.len() > 0 {
let mut max_sent = 0;
let lucky_peers_len = lucky_peers.len();
for (peer_id, sent, rlp) in lucky_peers {
peers.insert(peer_id);
self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp);
trace!(target: "sync", "{:02} <- Transactions ({} entries)", peer_id, sent);
max_sent = max(max_sent, sent);
}
debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, peers);
debug!(target: "sync", "Sent up to {} transactions to {} peers.", max_sent, lucky_peers_len);
}
peers
}
@ -2119,12 +2160,30 @@ impl ChainSync {
}
}
/// Checks if peer is able to process service transactions
fn accepts_service_transaction(client_id: &str) -> bool {
// Parity versions starting from this will accept service-transactions
const SERVICE_TRANSACTIONS_VERSION: (u32, u32) = (1u32, 6u32);
// Parity client string prefix
const PARITY_CLIENT_ID_PREFIX: &'static str = "Parity/v";
if !client_id.starts_with(PARITY_CLIENT_ID_PREFIX) {
return false;
}
let ver: Vec<u32> = client_id[PARITY_CLIENT_ID_PREFIX.len()..].split('.')
.take(2)
.filter_map(|s| s.parse().ok())
.collect();
ver.len() == 2 && (ver[0] > SERVICE_TRANSACTIONS_VERSION.0 || (ver[0] == SERVICE_TRANSACTIONS_VERSION.0 && ver[1] >= SERVICE_TRANSACTIONS_VERSION.1))
}
#[cfg(test)]
mod tests {
use std::collections::{HashSet, VecDeque};
use network::PeerId;
use tests::helpers::*;
use tests::snapshot::TestSnapshotService;
use util::{U256, RwLock};
use util::{Uint, U256, RwLock};
use util::sha3::Hashable;
use util::hash::{H256, FixedHash};
use util::bytes::Bytes;
@ -2134,6 +2193,7 @@ mod tests {
use super::{PeerInfo, PeerAsking};
use ethcore::header::*;
use ethcore::client::*;
use ethcore::transaction::SignedTransaction;
use ethcore::miner::MinerService;
fn get_dummy_block(order: u32, parent_hash: H256) -> Bytes {
@ -2359,7 +2419,12 @@ mod tests {
fn dummy_sync_with_peer(peer_latest_hash: H256, client: &BlockChainClient) -> ChainSync {
let mut sync = ChainSync::new(SyncConfig::default(), client);
sync.peers.insert(0,
insert_dummy_peer(&mut sync, 0, peer_latest_hash);
sync
}
fn insert_dummy_peer(sync: &mut ChainSync, peer_id: PeerId, peer_latest_hash: H256) {
sync.peers.insert(peer_id,
PeerInfo {
protocol_version: 0,
genesis: H256::zero(),
@ -2378,7 +2443,7 @@ mod tests {
asking_snapshot_data: None,
block_set: None,
});
sync
}
#[test]
@ -2630,6 +2695,79 @@ mod tests {
assert_eq!(stats.len(), 1, "Should maintain stats for single transaction.")
}
#[test]
fn should_propagate_service_transaction_to_selected_peers_only() {
let mut client = TestBlockChainClient::new();
client.insert_transaction_with_gas_price_to_queue(U256::zero());
let block_hash = client.block_hash_delta_minus(1);
let mut sync = ChainSync::new(SyncConfig::default(), &client);
let queue = RwLock::new(VecDeque::new());
let ss = TestSnapshotService::new();
let mut io = TestIo::new(&mut client, &ss, &queue, None);
// when peer#1 is Geth
insert_dummy_peer(&mut sync, 1, block_hash);
io.peers_info.insert(1, "Geth".to_owned());
// and peer#2 is Parity, accepting service transactions
insert_dummy_peer(&mut sync, 2, block_hash);
io.peers_info.insert(2, "Parity/v1.6".to_owned());
// and peer#3 is Parity, discarding service transactions
insert_dummy_peer(&mut sync, 3, block_hash);
io.peers_info.insert(3, "Parity/v1.5".to_owned());
// and peer#4 is Parity, accepting service transactions
insert_dummy_peer(&mut sync, 4, block_hash);
io.peers_info.insert(4, "Parity/v1.7.3-ABCDEFGH".to_owned());
// and new service transaction is propagated to peers
sync.propagate_new_transactions(&mut io);
// peer#2 && peer#4 are receiving service transaction
assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 2)); // TRANSACTIONS_PACKET
assert!(io.packets.iter().any(|p| p.packet_id == 0x02 && p.recipient == 4)); // TRANSACTIONS_PACKET
assert_eq!(io.packets.len(), 2);
}
#[test]
fn should_propagate_service_transaction_is_sent_as_separate_message() {
let mut client = TestBlockChainClient::new();
let tx1_hash = client.insert_transaction_to_queue();
let tx2_hash = client.insert_transaction_with_gas_price_to_queue(U256::zero());
let block_hash = client.block_hash_delta_minus(1);
let mut sync = ChainSync::new(SyncConfig::default(), &client);
let queue = RwLock::new(VecDeque::new());
let ss = TestSnapshotService::new();
let mut io = TestIo::new(&mut client, &ss, &queue, None);
// when peer#1 is Parity, accepting service transactions
insert_dummy_peer(&mut sync, 1, block_hash);
io.peers_info.insert(1, "Parity/v1.6".to_owned());
// and service + non-service transactions are propagated to peers
sync.propagate_new_transactions(&mut io);
// two separate packets for peer are queued:
// 1) with non-service-transaction
// 2) with service transaction
let sent_transactions: Vec<SignedTransaction> = io.packets.iter()
.filter_map(|p| {
if p.packet_id != 0x02 || p.recipient != 1 { // TRANSACTIONS_PACKET
return None;
}
let rlp = UntrustedRlp::new(&*p.data);
let item_count = rlp.item_count();
if item_count != 1 {
return None;
}
rlp.at(0).ok().and_then(|r| r.as_val().ok())
})
.collect();
assert_eq!(sent_transactions.len(), 2);
assert!(sent_transactions.iter().any(|tx| tx.hash() == tx1_hash));
assert!(sent_transactions.iter().any(|tx| tx.hash() == tx2_hash));
}
#[test]
fn handles_peer_new_block_malformed() {
let mut client = TestBlockChainClient::new();

View File

@ -49,6 +49,7 @@ pub struct TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p {
pub sender: Option<PeerId>,
pub to_disconnect: HashSet<PeerId>,
pub packets: Vec<TestPacket>,
pub peers_info: HashMap<PeerId, String>,
overlay: RwLock<HashMap<BlockNumber, Bytes>>,
}
@ -62,6 +63,7 @@ impl<'p, C> TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p {
to_disconnect: HashSet::new(),
overlay: RwLock::new(HashMap::new()),
packets: Vec::new(),
peers_info: HashMap::new(),
}
}
}
@ -111,6 +113,12 @@ impl<'p, C> SyncIo for TestIo<'p, C> where C: FlushingBlockChainClient, C: 'p {
&*self.chain
}
fn peer_info(&self, peer_id: PeerId) -> String {
self.peers_info.get(&peer_id)
.cloned()
.unwrap_or_else(|| peer_id.to_string())
}
fn snapshot_service(&self) -> &SnapshotService {
self.snapshot_service
}

View File

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

View File

@ -9,8 +9,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
futures = "0.1"
futures-cpupool = "0.1"
parking_lot = "0.3"
log = "0.3"
reqwest = "0.2"
reqwest = "0.4"
mime = "0.2"
clippy = { version = "0.0.90", optional = true}

View File

@ -16,13 +16,14 @@
//! Fetching
use std::{io, fmt};
use std::{io, fmt, time};
use std::sync::Arc;
use std::sync::atomic::{self, AtomicBool};
use futures::{self, BoxFuture, Future};
use futures_cpupool::{CpuPool, CpuFuture};
use mime::{self, Mime};
use parking_lot::RwLock;
use reqwest;
#[derive(Default, Debug, Clone)]
@ -71,24 +72,52 @@ pub trait Fetch: Clone + Send + Sync + 'static {
fn close(self) where Self: Sized {}
}
#[derive(Clone)]
const CLIENT_TIMEOUT_SECONDS: u64 = 5;
pub struct Client {
client: Arc<reqwest::Client>,
client: RwLock<(time::Instant, Arc<reqwest::Client>)>,
pool: CpuPool,
limit: Option<usize>,
}
impl Clone for Client {
fn clone(&self) -> Self {
let (ref time, ref client) = *self.client.read();
Client {
client: RwLock::new((time.clone(), client.clone())),
pool: self.pool.clone(),
limit: self.limit.clone(),
}
}
}
impl Client {
fn with_limit(limit: Option<usize>) -> Result<Self, Error> {
fn new_client() -> Result<Arc<reqwest::Client>, Error> {
let mut client = reqwest::Client::new()?;
client.redirect(reqwest::RedirectPolicy::limited(5));
Ok(Arc::new(client))
}
fn with_limit(limit: Option<usize>) -> Result<Self, Error> {
Ok(Client {
client: Arc::new(client),
client: RwLock::new((time::Instant::now(), Self::new_client()?)),
pool: CpuPool::new(4),
limit: limit,
})
}
fn client(&self) -> Result<Arc<reqwest::Client>, Error> {
{
let (ref time, ref client) = *self.client.read();
if time.elapsed() < time::Duration::from_secs(CLIENT_TIMEOUT_SECONDS) {
return Ok(client.clone());
}
}
let client = Self::new_client()?;
*self.client.write() = (time::Instant::now(), client.clone());
Ok(client)
}
}
impl Fetch for Client {
@ -108,12 +137,19 @@ impl Fetch for Client {
fn fetch_with_abort(&self, url: &str, abort: Abort) -> Self::Result {
debug!(target: "fetch", "Fetching from: {:?}", url);
match self.client() {
Ok(client) => {
self.pool.spawn(FetchTask {
url: url.into(),
client: self.client.clone(),
client: client,
limit: self.limit,
abort: abort,
})
},
Err(err) => {
self.pool.spawn(futures::future::err(err))
},
}
}
}

View File

@ -21,6 +21,7 @@ extern crate log;
extern crate futures;
extern crate futures_cpupool;
extern crate parking_lot;
extern crate reqwest;
pub extern crate mime;

View File

@ -517,13 +517,13 @@ impl Host {
}
pub fn external_url(&self) -> Option<String> {
self.info.read().public_endpoint.as_ref().map(|e| format!("{}", Node::new(self.info.read().id().clone(), e.clone())))
let info = self.info.read();
info.public_endpoint.as_ref().map(|e| format!("{}", Node::new(info.id().clone(), e.clone())))
}
pub fn local_url(&self) -> String {
let r = format!("{}", Node::new(self.info.read().id().clone(), self.info.read().local_endpoint.clone()));
println!("{}", r);
r
let info = self.info.read();
format!("{}", Node::new(info.id().clone(), info.local_endpoint.clone()))
}
pub fn stop(&self, io: &IoContext<NetworkIoMessage>) -> Result<(), NetworkError> {