[beta] Backports (#8916)

* `duration_ns: u64 -> duration: Duration` (#8457)

* duration_ns: u64 -> duration: Duration

* format on millis {:.2} -> {}

* Keep all enacted blocks notify in order (#8524)

* Keep all enacted blocks notify in order

* Collect is unnecessary

* Update ChainNotify to use ChainRouteType

* Fix all ethcore fn defs

* Wrap the type within ChainRoute

* Fix private-tx and sync api

* Fix secret_store API

* Fix updater API

* Fix rpc api

* Fix informant api

* Eagerly cache enacted/retracted and remove contain_enacted/retracted

* Fix indent

* tests: should use full expr form for struct constructor

* Use into_enacted_retracted to further avoid copy

* typo: not a function

* rpc/tests: ChainRoute -> ChainRoute::new

* Handle removed logs in filter changes and add geth compatibility field (#8796)

* Add removed geth compatibility field in log

* Fix mocked tests

* Add field block hash in PollFilter

* Store last block hash info for log filters

* Implement canon route

* Use canon logs for fetching reorg logs

Light client removed logs fetching is disabled. It looks expensive.

* Make sure removed flag is set

* Address grumbles

* Fixed AuthorityRound deadlock on shutdown, closes #8088 (#8803)

* CI: Fix docker tags (#8822)

* scripts: enable docker builds for beta and stable

* scripts: docker latest should be beta not master

* scripts: docker latest is master

* ethcore: fix ancient block error msg handling (#8832)

* Disable parallel verification and skip verifiying already imported txs. (#8834)

* Reject transactions that are already in pool without verifying them.

* Avoid verifying already imported transactions.

* Fix concurrent access to signer queue (#8854)

* Fix concurrent access to signer queue

* Put request back to the queue if confirmation failed

* typo: fix docs and rename functions to be more specific

`request_notify` does not need to be public, and it's renamed to `notify_result`.
`notify` is renamed to `notify_message`.

* Change trace info "Transaction" -> "Request"

* Don't allocate in expect_valid_rlp unless necessary (#8867)

* don't allocate via format! in case there's no error

* fix test?

* fixed ipc leak, closes #8774 (#8876)

* Add new ovh bootnodes and fix port for foundation bootnode 3.2 (#8886)

* Add new ovh bootnodes and fix port for foundation bootnode 3.2

* Remove old bootnodes.

* Remove duplicate 1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082

* Block 0 is valid in queries (#8891)

Early exit for block nr 0 leads to spurious error about pruning: `…your node is running with state pruning…`.

Fixes #7547, #8762

* Add ETC Cooperative-run load balanced parity node (#8892)

* Minor fix in chain supplier and light provider (#8906)

* fix chain supplier increment

* fix light provider block_headers

* Check whether we need resealing in miner and unwrap has_account in account_provider (#8853)

* Remove unused Result wrap in has_account

* Check whether we need to reseal for external transactions

* Fix reference to has_account interface

* typo: missing )

* Refactor duplicates to prepare_and_update_sealing

* Fix build

* Allow disabling local-by-default for transactions with new config entry (#8882)

* Add tx_queue_allow_unknown_local config option

- Previous commit messages:

dispatcher checks if we have the sender account

Add `tx_queue_allow_unknown_local` to MinerOptions

Add `tx_queue_allow_unknown_local` to config

fix order in MinerOptions to match Configuration

add cli flag for tx_queue_allow_unknown_local

Update refs to `tx_queue_allow_unknown_local`

Add tx_queue_allow_unknown_local to config test

revert changes to dispatcher

Move tx_queue_allow_unknown_local to `import_own_transaction`

Fix var name

if statement should return the values

derp de derp derp derp semicolons

Reset dispatch file to how it was before

fix compile issues + change from FLAG to ARG

add test and use `into`

import MinerOptions, clone the secret

Fix tests?

Compiler/linter issues fixed

Fix linter msg - case of constants

IT LIVES

refactor to omit yucky explict return

update comments

Fix based on diff AccountProvider.has_account method

* Refactor flag name + don't change import_own_tx behaviour

fix arg name

Note: force commit to try and get gitlab tests working again 😠

* Add fn to TestMinerService

* Avoid race condition from trusted sources

- refactor the miner tests a bit to cut down on code reuse
- add `trusted` param to dispatch_transaction and import_claimed_local_transaction

Add param to `import_claimed_local_transaction`

Fix fn sig in tests
This commit is contained in:
André Silva 2018-06-19 09:41:14 +01:00 committed by Afri Schoedon
parent f26a7fe6fa
commit cc44ae9cb5
52 changed files with 659 additions and 323 deletions

View File

@ -201,6 +201,8 @@ docker-build:
stage: build stage: build
only: only:
- tags - tags
- beta
- stable
- triggers - triggers
before_script: before_script:
- docker info - docker info

70
Cargo.lock generated
View File

@ -687,7 +687,6 @@ dependencies = [
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"price-info 1.11.0", "price-info 1.11.0",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.2.1", "rlp 0.2.1",
"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)",
"trace-time 0.1.0", "trace-time 0.1.0",
@ -1358,7 +1357,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-core" name = "jsonrpc-core"
version = "8.0.1" version = "8.0.1"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1370,7 +1369,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-http-server" name = "jsonrpc-http-server"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.24 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
@ -1383,7 +1382,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-ipc-server" name = "jsonrpc-ipc-server"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
"jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
@ -1395,7 +1394,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-macros" name = "jsonrpc-macros"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
"jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
@ -1405,7 +1404,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-pubsub" name = "jsonrpc-pubsub"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1415,7 +1414,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-server-utils" name = "jsonrpc-server-utils"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1428,7 +1427,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-tcp-server" name = "jsonrpc-tcp-server"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
"jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
@ -1440,7 +1439,7 @@ dependencies = [
[[package]] [[package]]
name = "jsonrpc-ws-server" name = "jsonrpc-ws-server"
version = "8.0.0" version = "8.0.0"
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#06bec6ab682ec4ce16d7e7daf2612870c4272028" source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11#c8e6336798be4444953def351099078617d40efd"
dependencies = [ dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)", "jsonrpc-core 8.0.1 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.11)",
@ -1724,14 +1723,13 @@ dependencies = [
[[package]] [[package]]
name = "mio-named-pipes" name = "mio-named-pipes"
version = "0.1.4" version = "0.1.5"
source = "git+https://github.com/alexcrichton/mio-named-pipes#9c1bbb985b74374d3b7eda76937279f8e977ef81" source = "git+https://github.com/alexcrichton/mio-named-pipes#6ad80e67fe7993423b281bc13d307785ade05d37"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1754,6 +1752,15 @@ dependencies = [
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "miow"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "msdos_time" name = "msdos_time"
version = "0.1.6" version = "0.1.6"
@ -2252,12 +2259,12 @@ dependencies = [
[[package]] [[package]]
name = "parity-tokio-ipc" name = "parity-tokio-ipc"
version = "0.1.5" version = "0.1.5"
source = "git+https://github.com/nikvolf/parity-tokio-ipc#d6c5b3cfcc913a1b9cf0f0562a10b083ceb9fb7c" source = "git+https://github.com/nikvolf/parity-tokio-ipc#2af3e5b6b746552d8181069a2c6be068377df1de"
dependencies = [ dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2691,7 +2698,7 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.1.31" version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -2699,7 +2706,7 @@ name = "redox_termios"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -3035,6 +3042,17 @@ dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "socket2"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "stable_deref_trait" name = "stable_deref_trait"
version = "1.0.0" version = "1.0.0"
@ -3139,7 +3157,7 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -3168,7 +3186,7 @@ version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -3204,7 +3222,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -3275,7 +3293,7 @@ source = "git+https://github.com/nikvolf/tokio-named-pipes#0b9b728eaeb0a6673c287
dependencies = [ dependencies = [
"bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)", "mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -3899,9 +3917,10 @@ dependencies = [
"checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398" "checksum miniz_oxide 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aaa2d3ad070f428fffbd7d3ca2ea20bb0d8cffe9024405c44e1840bc1418b398"
"checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5" "checksum miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "92d98fdbd6145645828069b37ea92ca3de225e000d80702da25c20d3584b38a5"
"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe"
"checksum mio-named-pipes 0.1.4 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>" "checksum mio-named-pipes 0.1.5 (git+https://github.com/alexcrichton/mio-named-pipes)" = "<none>"
"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" "checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d"
"checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729" "checksum msdos_time 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aad9dfe950c057b1bfe9c1f2aa51583a8468ef2a5baba2ebbe06d775efeb7729"
"checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6" "checksum multibase 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9c35dac080fd6e16a99924c8dfdef0af89d797dd851adab25feaffacf7850d6"
"checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3" "checksum multihash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d49add5f49eb08bfc4d01ff286b84a48f53d45314f165c2d6efe477222d24f3"
@ -3955,7 +3974,7 @@ dependencies = [
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1"
"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa" "checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
@ -3994,6 +4013,7 @@ dependencies = [
"checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d" "checksum smallvec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fcd03faf178110ab0334d74ca9631d77f94c8c11cc77fcb59538abf0025695d"
"checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>" "checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>"
"checksum socket2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "06dc9f86ee48652b7c80f3d254e3b9accb67a928c562c64d10d7b016d3d98dab"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb" "checksum subtle 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc7f6353c2ee5407358d063a14cccc1630804527090a6fb5a9489ce4924280fb"

View File

@ -54,6 +54,7 @@ pub trait Provider: Send + Sync {
/// results within must adhere to the `skip` and `reverse` parameters. /// results within must adhere to the `skip` and `reverse` parameters.
fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option<request::HeadersResponse> { fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option<request::HeadersResponse> {
use request::HashOrNumber; use request::HashOrNumber;
const MAX_HEADERS_TO_SEND: u64 = 512;
if req.max == 0 { return None } if req.max == 0 { return None }
@ -82,10 +83,12 @@ pub trait Provider: Send + Sync {
} }
}; };
let headers: Vec<_> = (0u64..req.max as u64) let max = ::std::cmp::min(MAX_HEADERS_TO_SEND, req.max);
.map(|x: u64| x.saturating_mul(req.skip + 1))
let headers: Vec<_> = (0u64..max)
.map(|x: u64| x.saturating_mul(req.skip.saturating_add(1)))
.take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x }) .take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x })
.map(|x| if req.reverse { start_num - x } else { start_num + x }) .map(|x| if req.reverse { start_num.saturating_sub(x) } else { start_num.saturating_add(x) })
.map(|x| self.block_header(BlockId::Number(x))) .map(|x| self.block_header(BlockId::Number(x)))
.take_while(|x| x.is_some()) .take_while(|x| x.is_some())
.flat_map(|x| x) .flat_map(|x| x)

View File

@ -66,6 +66,7 @@ pub use error::{Error, ErrorKind};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::time::Duration;
use ethereum_types::{H128, H256, U256, Address}; use ethereum_types::{H128, H256, U256, Address};
use hash::keccak; use hash::keccak;
use rlp::*; use rlp::*;
@ -78,7 +79,7 @@ use ethcore::executed::{Executed};
use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction}; use transaction::{SignedTransaction, Transaction, Action, UnverifiedTransaction};
use ethcore::{contract_address as ethcore_contract_address}; use ethcore::{contract_address as ethcore_contract_address};
use ethcore::client::{ use ethcore::client::{
Client, ChainNotify, ChainMessageType, ClientIoMessage, BlockId, CallContract Client, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage, BlockId, CallContract
}; };
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use ethcore::miner::{self, Miner, MinerService}; use ethcore::miner::{self, Miner, MinerService};
@ -679,7 +680,7 @@ fn find_account_password(passwords: &Vec<String>, account_provider: &AccountProv
} }
impl ChainNotify for Provider { impl ChainNotify for Provider {
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) { fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
if !imported.is_empty() { if !imported.is_empty() {
trace!("New blocks imported, try to prune the queue"); trace!("New blocks imported, try to prune the queue");
if let Err(err) = self.process_queue() { if let Err(err) = self.process_queue() {

View File

@ -57,7 +57,8 @@
"enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303", "enode://814920f1ec9510aa9ea1c8f79d8b6e6a462045f09caa2ae4055b0f34f7416fca6facd3dd45f1cf1673c0209e0503f02776b8ff94020e98b6679a0dc561b4eba0@104.154.136.117:30303",
"enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303", "enode://72e445f4e89c0f476d404bc40478b0df83a5b500d2d2e850e08eb1af0cd464ab86db6160d0fde64bd77d5f0d33507ae19035671b3c74fec126d6e28787669740@104.198.71.200:30303",
"enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303", "enode://39abab9d2a41f53298c0c9dc6bbca57b0840c3ba9dccf42aa27316addc1b7e56ade32a0a9f7f52d6c5db4fe74d8824bcedfeaecf1a4e533cacb71cf8100a9442@144.76.238.49:30303",
"enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306" "enode://f50e675a34f471af2438b921914b5f06499c7438f3146f6b8936f1faeb50b8a91d0d0c24fb05a66f05865cd58c24da3e664d0def806172ddd0d4c5bdbf37747e@144.76.238.49:30306",
"enode://83b33409349ffa25e150555f7b4f8deebc68f3d34d782129dc3c8ba07b880c209310a4191e1725f2f6bef59bce9452d821111eaa786deab08a7e6551fca41f4f@159.89.223.6:30303"
], ],
"accounts": { "accounts": {
"0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },

View File

@ -2866,16 +2866,13 @@
] ]
}, },
"nodes": [ "nodes": [
"enode://81863f47e9bd652585d3f78b4b2ee07b93dad603fd9bc3c293e1244250725998adc88da0cef48f1de89b15ab92b15db8f43dc2b6fb8fbd86a6f217a1dd886701@193.70.55.37:30303",
"enode://4afb3a9137a88267c02651052cf6fb217931b8c78ee058bb86643542a4e2e0a8d24d47d871654e1b78a276c363f3c1bc89254a973b00adc359c9e9a48f140686@144.217.139.5:30303",
"enode://c16d390b32e6eb1c312849fe12601412313165df1a705757d671296f1ac8783c5cff09eab0118ac1f981d7148c85072f0f26407e5c68598f3ad49209fade404d@139.99.51.203:30303",
"enode://4faf867a2e5e740f9b874e7c7355afee58a2d1ace79f7b692f1d553a1134eddbeb5f9210dd14dc1b774a46fd5f063a8bc1fa90579e13d9d18d1f59bac4a4b16b@139.99.160.213:30303",
"enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303", "enode://6a868ced2dec399c53f730261173638a93a40214cf299ccf4d42a76e3fa54701db410669e8006347a4b3a74fa090bb35af0320e4bc8d04cf5b7f582b1db285f5@163.172.131.191:30303",
"enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303", "enode://66a483383882a518fcc59db6c017f9cd13c71261f13c8d7e67ed43adbbc82a932d88d2291f59be577e9425181fc08828dc916fdd053af935a9491edf9d6006ba@212.47.247.103:30303",
"enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303", "enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@163.172.157.114:30303",
"enode://78b094cb27ceeecbe311bc278f4fde8b9a265db42d268c88484c94d7a2d19b82a1bd22dfd6c2bd4d90f9b05e6d42255e6eb85de15f73848ff82ed0be9cdf5202@52.233.198.218:30303",
"enode://00526537cb7e1aa6cf49714f0635fd0f608904d8d0693b949eea2dcdfdb0abbe4c794003a5fe57aa662d0a9215e8dfa4d2deb6ef0101c5e185e2617721813d43@40.65.122.44:30303",
"enode://4a456b4b6e6ee1f51389763e51b80fe04782c762445d96c32a96ebd34bd9178c1894924d5101123eacfd4f0fc4da25b5e1ee7f18832ac0bf4c6d6ac81442d698@40.71.6.49:3030",
"enode://68f85e7403976aa92318eff804cbe9bc988e0f5230d9d07ae4def030cbae16603262638e272d19875b7e5c54e296ba88ab6ec6e98face9e2537346c4dce78882@52.243.47.211:30303",
"enode://dc72806c3aa8fda207c8c018aba8d6cf143728b3628b6ded8d5e8cdeb8aa05cbd53f710ecd014c9a8f0d1e98f2874bff8afb15a229202f510a9c0258d1f6d109@159.203.210.80:30303",
"enode://5a62f19d35c0da8b576c9414568c728d4744e6e9d436c0f9db27456400011414f515871f13a6b8e0468534b5116cfe765d7630f680f1707a38467940a9f62511@45.55.33.62:30303",
"enode://605e04a43b1156966b3a3b66b980c87b7f18522f7f712035f84576016be909a2798a438b2b17b1a8c58db314d88539a77419ca4be36148c086900fba487c9d39@188.166.255.12:30303",
"enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303", "enode://1d1f7bcb159d308eb2f3d5e32dc5f8786d714ec696bb2f7e3d982f9bcd04c938c139432f13aadcaf5128304a8005e8606aebf5eebd9ec192a1471c13b5e31d49@138.201.223.35:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", "enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303", "enode://3f1d12044546b76342d59d4a05532c14b85aa669704bfe1f864fe079415aa2c02d743e03218e57a33fb94523adb54032871a6c51b2cc5514cb7c7e35b3ed0a99@13.93.211.84:30303",
@ -2887,7 +2884,6 @@
"enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308", "enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308",
"enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309", "enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309",
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", "enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303", "enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@138.201.144.135:30303",
"enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303", "enode://01f76fa0561eca2b9a7e224378dd854278735f1449793c46ad0c4e79e8775d080c21dcc455be391e90a98153c3b05dcc8935c8440de7b56fe6d67251e33f4e3c@51.15.42.252:30303",
"enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303", "enode://2c9059f05c352b29d559192fe6bca272d965c9f2290632a2cfda7f83da7d2634f3ec45ae3a72c54dd4204926fb8082dcf9686e0d7504257541c86fc8569bcf4b@163.172.171.38:30303",

View File

@ -272,8 +272,8 @@ 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) -> bool {
Ok(self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)) self.sstore.account_ref(&address).is_ok() && !self.blacklisted_accounts.contains(&address)
} }
/// Returns addresses of all accounts. /// Returns addresses of all accounts.

View File

@ -20,7 +20,7 @@ use ethereum_types::H256;
use blockchain::block_info::{BlockInfo, BlockLocation}; use blockchain::block_info::{BlockInfo, BlockLocation};
/// Import route for newly inserted block. /// Import route for newly inserted block.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub struct ImportRoute { pub struct ImportRoute {
/// Blocks that were invalidated by new block. /// Blocks that were invalidated by new block.
pub retracted: Vec<H256>, pub retracted: Vec<H256>,

View File

@ -17,6 +17,9 @@
use bytes::Bytes; use bytes::Bytes;
use ethereum_types::H256; use ethereum_types::H256;
use transaction::UnverifiedTransaction; use transaction::UnverifiedTransaction;
use blockchain::ImportRoute;
use std::time::Duration;
use std::collections::HashMap;
/// Messages to broadcast via chain /// Messages to broadcast via chain
pub enum ChainMessageType { pub enum ChainMessageType {
@ -28,6 +31,89 @@ pub enum ChainMessageType {
SignedPrivateTransaction(Vec<u8>), SignedPrivateTransaction(Vec<u8>),
} }
/// Route type to indicate whether it is enacted or retracted.
#[derive(Clone)]
pub enum ChainRouteType {
/// Enacted block
Enacted,
/// Retracted block
Retracted
}
/// A complete chain enacted retracted route.
#[derive(Default, Clone)]
pub struct ChainRoute {
route: Vec<(H256, ChainRouteType)>,
enacted: Vec<H256>,
retracted: Vec<H256>,
}
impl<'a> From<&'a [ImportRoute]> for ChainRoute {
fn from(import_results: &'a [ImportRoute]) -> ChainRoute {
ChainRoute::new(import_results.iter().flat_map(|route| {
route.retracted.iter().map(|h| (*h, ChainRouteType::Retracted))
.chain(route.enacted.iter().map(|h| (*h, ChainRouteType::Enacted)))
}).collect())
}
}
impl ChainRoute {
/// Create a new ChainRoute based on block hash and route type pairs.
pub fn new(route: Vec<(H256, ChainRouteType)>) -> Self {
let (enacted, retracted) = Self::to_enacted_retracted(&route);
Self { route, enacted, retracted }
}
/// Gather all non-duplicate enacted and retracted blocks.
fn to_enacted_retracted(route: &[(H256, ChainRouteType)]) -> (Vec<H256>, Vec<H256>) {
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
map.into_iter().map(|(k, _v)| k).collect()
}
// Because we are doing multiple inserts some of the blocks that were enacted in import `k`
// could be retracted in import `k+1`. This is why to understand if after all inserts
// the block is enacted or retracted we iterate over all routes and at the end final state
// will be in the hashmap
let map = route.iter().fold(HashMap::new(), |mut map, route| {
match &route.1 {
&ChainRouteType::Enacted => {
map.insert(route.0, true);
},
&ChainRouteType::Retracted => {
map.insert(route.0, false);
},
}
map
});
// Split to enacted retracted (using hashmap value)
let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v);
// And convert tuples to keys
(map_to_vec(enacted), map_to_vec(retracted))
}
/// Consume route and return the enacted retracted form.
pub fn into_enacted_retracted(self) -> (Vec<H256>, Vec<H256>) {
(self.enacted, self.retracted)
}
/// All non-duplicate enacted blocks.
pub fn enacted(&self) -> &[H256] {
&self.enacted
}
/// All non-duplicate retracted blocks.
pub fn retracted(&self) -> &[H256] {
&self.retracted
}
/// All blocks in the route.
pub fn route(&self) -> &[(H256, ChainRouteType)] {
&self.route
}
}
/// Represents what has to be handled by actor listening to chain events /// Represents what has to be handled by actor listening to chain events
pub trait ChainNotify : Send + Sync { pub trait ChainNotify : Send + Sync {
/// fires when chain has new blocks. /// fires when chain has new blocks.
@ -35,12 +121,11 @@ pub trait ChainNotify : Send + Sync {
&self, &self,
_imported: Vec<H256>, _imported: Vec<H256>,
_invalid: Vec<H256>, _invalid: Vec<H256>,
_enacted: Vec<H256>, _route: ChainRoute,
_retracted: Vec<H256>,
_sealed: Vec<H256>, _sealed: Vec<H256>,
// Block bytes. // Block bytes.
_proposed: Vec<Bytes>, _proposed: Vec<Bytes>,
_duration: u64, _duration: Duration,
) { ) {
// does nothing by default // does nothing by default
} }

View File

@ -14,12 +14,12 @@
// 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 std::collections::{HashSet, HashMap, BTreeMap, BTreeSet, VecDeque}; use std::collections::{HashSet, BTreeMap, BTreeSet, VecDeque};
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant}; use std::time::{Instant, Duration};
// util // util
use hash::keccak; use hash::keccak;
@ -33,7 +33,7 @@ use util_error::UtilError;
// other // other
use ethereum_types::{H256, Address, U256}; use ethereum_types::{H256, Address, U256};
use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock}; use block::{IsBlock, LockedBlock, Drain, ClosedBlock, OpenBlock, enact_verified, SealedBlock};
use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute, TransactionAddress};
use client::ancient_import::AncientVerifier; use client::ancient_import::AncientVerifier;
use client::Error as ClientError; use client::Error as ClientError;
use client::{ use client::{
@ -46,8 +46,8 @@ use client::{
use client::{ use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
TraceFilter, CallAnalytics, BlockImportError, Mode, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType, ChainMessageType, ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient,
IoClient, EngineInfo, IoClient,
}; };
use encoded; use encoded;
use engines::{EthEngine, EpochTransition}; use engines::{EthEngine, EpochTransition};
@ -125,7 +125,7 @@ impl<'a> ::std::ops::Sub<&'a ClientReport> for ClientReport {
self.blocks_imported -= other.blocks_imported; self.blocks_imported -= other.blocks_imported;
self.transactions_applied -= other.transactions_applied; self.transactions_applied -= other.transactions_applied;
self.gas_processed = self.gas_processed - other.gas_processed; self.gas_processed = self.gas_processed - other.gas_processed;
self.state_db_mem = higher_mem - lower_mem; self.state_db_mem = higher_mem - lower_mem;
self self
} }
@ -257,32 +257,6 @@ impl Importer {
}) })
} }
fn calculate_enacted_retracted(&self, import_results: &[ImportRoute]) -> (Vec<H256>, Vec<H256>) {
fn map_to_vec(map: Vec<(H256, bool)>) -> Vec<H256> {
map.into_iter().map(|(k, _v)| k).collect()
}
// In ImportRoute we get all the blocks that have been enacted and retracted by single insert.
// Because we are doing multiple inserts some of the blocks that were enacted in import `k`
// could be retracted in import `k+1`. This is why to understand if after all inserts
// the block is enacted or retracted we iterate over all routes and at the end final state
// will be in the hashmap
let map = import_results.iter().fold(HashMap::new(), |mut map, route| {
for hash in &route.enacted {
map.insert(hash.clone(), true);
}
for hash in &route.retracted {
map.insert(hash.clone(), false);
}
map
});
// Split to enacted retracted (using hashmap value)
let (enacted, retracted) = map.into_iter().partition(|&(_k, v)| v);
// And convert tuples to keys
(map_to_vec(enacted), map_to_vec(retracted))
}
/// This is triggered by a message coming from a block queue when the block is ready for insertion /// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self, client: &Client) -> usize { pub fn import_verified_blocks(&self, client: &Client) -> usize {
@ -343,27 +317,22 @@ impl Importer {
self.block_queue.mark_as_bad(&invalid_blocks); self.block_queue.mark_as_bad(&invalid_blocks);
} }
let is_empty = self.block_queue.mark_as_good(&imported_blocks); let is_empty = self.block_queue.mark_as_good(&imported_blocks);
let duration_ns = { (imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, start.elapsed(), is_empty)
let elapsed = start.elapsed();
elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64
};
(imported_blocks, import_results, invalid_blocks, imported, proposed_blocks, duration_ns, is_empty)
}; };
{ {
if !imported_blocks.is_empty() && is_empty { if !imported_blocks.is_empty() && is_empty {
let (enacted, retracted) = self.calculate_enacted_retracted(&import_results); let route = ChainRoute::from(import_results.as_ref());
if is_empty { if is_empty {
self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, &enacted, &retracted, false); self.miner.chain_new_blocks(client, &imported_blocks, &invalid_blocks, route.enacted(), route.retracted(), false);
} }
client.notify(|notify| { client.notify(|notify| {
notify.new_blocks( notify.new_blocks(
imported_blocks.clone(), imported_blocks.clone(),
invalid_blocks.clone(), invalid_blocks.clone(),
enacted.clone(), route.clone(),
retracted.clone(),
Vec::new(), Vec::new(),
proposed_blocks.clone(), proposed_blocks.clone(),
duration, duration,
@ -1030,7 +999,8 @@ impl Client {
/// Otherwise, this can fail (but may not) if the DB prunes state. /// Otherwise, this can fail (but may not) if the DB prunes state.
pub fn state_at_beginning(&self, id: BlockId) -> Option<State<StateDB>> { pub fn state_at_beginning(&self, id: BlockId) -> Option<State<StateDB>> {
match self.block_number(id) { match self.block_number(id) {
None | Some(0) => None, None => None,
Some(0) => self.state_at(id),
Some(n) => self.state_at(BlockId::Number(n - 1)), Some(n) => self.state_at(BlockId::Number(n - 1)),
} }
} }
@ -1446,7 +1416,7 @@ impl Call for Client {
} }
fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result<U256, CallError> { fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result<U256, CallError> {
let (mut upper, max_upper, env_info) = { let (mut upper, max_upper, env_info) = {
let init = *header.gas_limit(); let init = *header.gas_limit();
let max = init * U256::from(10); let max = init * U256::from(10);
@ -2041,15 +2011,16 @@ impl IoClient for Client {
let first = queued.write().1.pop_front(); let first = queued.write().1.pop_front();
if let Some((header, block_bytes, receipts_bytes)) = first { if let Some((header, block_bytes, receipts_bytes)) = first {
let hash = header.hash(); let hash = header.hash();
client.importer.import_old_block( let result = client.importer.import_old_block(
&header, &header,
&block_bytes, &block_bytes,
&receipts_bytes, &receipts_bytes,
&**client.db.read(), &**client.db.read(),
&*client.chain.read() &*client.chain.read(),
).ok().map_or((), |e| { );
if let Err(e) = result {
error!(target: "client", "Error importing ancient block: {}", e); error!(target: "client", "Error importing ancient block: {}", e);
}); }
// remove from pending // remove from pending
queued.write().0.remove(&hash); queued.write().0.remove(&hash);
} else { } else {
@ -2171,20 +2142,16 @@ impl ImportSealedBlock for Client {
self.state_db.write().sync_cache(&route.enacted, &route.retracted, false); self.state_db.write().sync_cache(&route.enacted, &route.retracted, false);
route route
}; };
let (enacted, retracted) = self.importer.calculate_enacted_retracted(&[route]); let route = ChainRoute::from([route].as_ref());
self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], &enacted, &retracted, self.engine.seals_internally().is_some()); self.importer.miner.chain_new_blocks(self, &[h.clone()], &[], route.enacted(), route.retracted(), true);
self.notify(|notify| { self.notify(|notify| {
notify.new_blocks( notify.new_blocks(
vec![h.clone()], vec![h.clone()],
vec![], vec![],
enacted.clone(), route.clone(),
retracted.clone(),
vec![h.clone()], vec![h.clone()],
vec![], vec![],
{ start.elapsed(),
let elapsed = start.elapsed();
elapsed.as_secs() * 1_000_000_000 + elapsed.subsec_nanos() as u64
},
); );
}); });
self.db.read().flush().expect("DB flush failed."); self.db.read().flush().expect("DB flush failed.");
@ -2194,15 +2161,15 @@ impl ImportSealedBlock for Client {
impl BroadcastProposalBlock for Client { impl BroadcastProposalBlock for Client {
fn broadcast_proposal_block(&self, block: SealedBlock) { fn broadcast_proposal_block(&self, block: SealedBlock) {
const DURATION_ZERO: Duration = Duration::from_millis(0);
self.notify(|notify| { self.notify(|notify| {
notify.new_blocks( notify.new_blocks(
vec![], vec![],
vec![], vec![],
vec![], ChainRoute::default(),
vec![],
vec![], vec![],
vec![block.rlp_bytes()], vec![block.rlp_bytes()],
0, DURATION_ZERO,
); );
}); });
} }

View File

@ -31,7 +31,7 @@ pub use self::error::Error;
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult}; pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult};
pub use self::io_message::ClientIoMessage; pub use self::io_message::ClientIoMessage;
pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::chain_notify::{ChainNotify, ChainMessageType}; pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType};
pub use self::traits::{ pub use self::traits::{
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter

View File

@ -382,12 +382,16 @@ impl Decodable for SealedEmptyStep {
} }
} }
struct PermissionedStep {
inner: Step,
can_propose: AtomicBool,
}
/// Engine using `AuthorityRound` proof-of-authority BFT consensus. /// Engine using `AuthorityRound` proof-of-authority BFT consensus.
pub struct AuthorityRound { pub struct AuthorityRound {
transition_service: IoService<()>, transition_service: IoService<()>,
step: Arc<Step>, step: Arc<PermissionedStep>,
can_propose: AtomicBool, client: Arc<RwLock<Option<Weak<EngineClient>>>>,
client: RwLock<Option<Weak<EngineClient>>>,
signer: RwLock<EngineSigner>, signer: RwLock<EngineSigner>,
validators: Box<ValidatorSet>, validators: Box<ValidatorSet>,
validate_score_transition: u64, validate_score_transition: u64,
@ -407,7 +411,7 @@ pub struct AuthorityRound {
// header-chain validator. // header-chain validator.
struct EpochVerifier { struct EpochVerifier {
step: Arc<Step>, step: Arc<PermissionedStep>,
subchain_validators: SimpleList, subchain_validators: SimpleList,
empty_steps_transition: u64, empty_steps_transition: u64,
} }
@ -415,7 +419,7 @@ struct EpochVerifier {
impl super::EpochVerifier<EthereumMachine> for EpochVerifier { impl super::EpochVerifier<EthereumMachine> for EpochVerifier {
fn verify_light(&self, header: &Header) -> Result<(), Error> { fn verify_light(&self, header: &Header) -> Result<(), Error> {
// Validate the timestamp // Validate the timestamp
verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?)?; verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?)?;
// always check the seal since it's fast. // always check the seal since it's fast.
// nothing heavier to do. // nothing heavier to do.
verify_external(header, &self.subchain_validators, self.empty_steps_transition) verify_external(header, &self.subchain_validators, self.empty_steps_transition)
@ -615,13 +619,15 @@ impl AuthorityRound {
let engine = Arc::new( let engine = Arc::new(
AuthorityRound { AuthorityRound {
transition_service: IoService::<()>::start()?, transition_service: IoService::<()>::start()?,
step: Arc::new(Step { step: Arc::new(PermissionedStep {
inner: AtomicUsize::new(initial_step), inner: Step {
calibrate: our_params.start_step.is_none(), inner: AtomicUsize::new(initial_step),
duration: our_params.step_duration, calibrate: our_params.start_step.is_none(),
duration: our_params.step_duration,
},
can_propose: AtomicBool::new(true),
}), }),
can_propose: AtomicBool::new(true), client: Arc::new(RwLock::new(None)),
client: RwLock::new(None),
signer: Default::default(), signer: Default::default(),
validators: our_params.validators, validators: our_params.validators,
validate_score_transition: our_params.validate_score_transition, validate_score_transition: our_params.validate_score_transition,
@ -641,7 +647,10 @@ impl AuthorityRound {
// Do not initialize timeouts for tests. // Do not initialize timeouts for tests.
if should_timeout { if should_timeout {
let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; let handler = TransitionHandler {
step: engine.step.clone(),
client: engine.client.clone(),
};
engine.transition_service.register_handler(Arc::new(handler))?; engine.transition_service.register_handler(Arc::new(handler))?;
} }
Ok(engine) Ok(engine)
@ -667,7 +676,7 @@ impl AuthorityRound {
} }
fn generate_empty_step(&self, parent_hash: &H256) { fn generate_empty_step(&self, parent_hash: &H256) {
let step = self.step.load(); let step = self.step.inner.load();
let empty_step_rlp = empty_step_rlp(step, parent_hash); let empty_step_rlp = empty_step_rlp(step, parent_hash);
if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) { if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) {
@ -699,34 +708,37 @@ fn unix_now() -> Duration {
} }
struct TransitionHandler { struct TransitionHandler {
engine: Weak<AuthorityRound>, step: Arc<PermissionedStep>,
client: Arc<RwLock<Option<Weak<EngineClient>>>>,
} }
const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; const ENGINE_TIMEOUT_TOKEN: TimerToken = 23;
impl IoHandler<()> for TransitionHandler { impl IoHandler<()> for TransitionHandler {
fn initialize(&self, io: &IoContext<()>) { fn initialize(&self, io: &IoContext<()>) {
if let Some(engine) = self.engine.upgrade() { let remaining = self.step.inner.duration_remaining().as_millis();
let remaining = engine.step.duration_remaining().as_millis(); io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining))
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining)) .unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e))
.unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e))
}
} }
fn timeout(&self, io: &IoContext<()>, timer: TimerToken) { fn timeout(&self, io: &IoContext<()>, timer: TimerToken) {
if timer == ENGINE_TIMEOUT_TOKEN { if timer == ENGINE_TIMEOUT_TOKEN {
if let Some(engine) = self.engine.upgrade() { // NOTE we might be lagging by couple of steps in case the timeout
// NOTE we might be lagging by couple of steps in case the timeout // has not been called fast enough.
// has not been called fast enough. // Make sure to advance up to the actual step.
// Make sure to advance up to the actual step. while self.step.inner.duration_remaining().as_millis() == 0 {
while engine.step.duration_remaining().as_millis() == 0 { self.step.inner.increment();
engine.step(); self.step.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() {
c.update_sealing();
}
} }
let next_run_at = engine.step.duration_remaining().as_millis() >> 2;
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at))
.unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e))
} }
let next_run_at = self.step.inner.duration_remaining().as_millis() >> 2;
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at))
.unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e))
} }
} }
} }
@ -743,8 +755,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
} }
fn step(&self) { fn step(&self) {
self.step.increment(); self.step.inner.increment();
self.can_propose.store(true, AtomicOrdering::SeqCst); self.step.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() { if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() { if let Some(c) = weak.upgrade() {
c.update_sealing(); c.update_sealing();
@ -791,7 +803,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
fn populate_from_parent(&self, header: &mut Header, parent: &Header) { fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed"); let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed");
let current_step = self.step.load(); let current_step = self.step.inner.load();
let current_empty_steps_len = if header.number() >= self.empty_steps_transition { let current_empty_steps_len = if header.number() >= self.empty_steps_transition {
self.empty_steps(parent_step.into(), current_step.into(), parent.hash()).len() self.empty_steps(parent_step.into(), current_step.into(), parent.hash()).len()
@ -817,7 +829,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;; let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;;
if empty_step.verify(&*self.validators).unwrap_or(false) { if empty_step.verify(&*self.validators).unwrap_or(false) {
if self.step.check_future(empty_step.step).is_ok() { if self.step.inner.check_future(empty_step.step).is_ok() {
trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step); trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step);
self.handle_empty_step_message(empty_step); self.handle_empty_step_message(empty_step);
} else { } else {
@ -837,7 +849,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> 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) { if !self.step.can_propose.load(AtomicOrdering::SeqCst) {
trace!(target: "engine", "Aborting seal generation. Can't propose."); trace!(target: "engine", "Aborting seal generation. Can't propose.");
return Seal::None; return Seal::None;
} }
@ -846,7 +858,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
let parent_step: U256 = header_step(parent, self.empty_steps_transition) let parent_step: U256 = header_step(parent, self.empty_steps_transition)
.expect("Header has been verified; qed").into(); .expect("Header has been verified; qed").into();
let step = self.step.load(); let step = self.step.inner.load();
// filter messages from old and future steps and different parents // filter messages from old and future steps and different parents
let empty_steps = if header.number() >= self.empty_steps_transition { let empty_steps = if header.number() >= self.empty_steps_transition {
@ -923,7 +935,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step); trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
// only issue the seal if we were the first to reach the compare_and_swap. // only issue the seal if we were the first to reach the compare_and_swap.
if self.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) { if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
self.clear_empty_steps(parent_step); self.clear_empty_steps(parent_step);
@ -999,7 +1011,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
.decode()?; .decode()?;
let parent_step = header_step(&parent, self.empty_steps_transition)?; let parent_step = header_step(&parent, self.empty_steps_transition)?;
let current_step = self.step.load(); let current_step = self.step.inner.load();
self.empty_steps(parent_step.into(), current_step.into(), parent.hash()) self.empty_steps(parent_step.into(), current_step.into(), parent.hash())
} else { } else {
// we're verifying a block, extract empty steps from the seal // we're verifying a block, extract empty steps from the seal
@ -1049,7 +1061,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
// If yes then probably benign reporting needs to be moved further in the verification. // If yes then probably benign reporting needs to be moved further in the verification.
let set_number = header.number(); let set_number = header.number();
match verify_timestamp(&*self.step, header_step(header, self.empty_steps_transition)?) { match verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?) {
Err(BlockError::InvalidSeal) => { Err(BlockError::InvalidSeal) => {
self.validators.report_benign(header.author(), set_number, header.number()); self.validators.report_benign(header.author(), set_number, header.number());
Err(BlockError::InvalidSeal.into()) Err(BlockError::InvalidSeal.into())
@ -1291,7 +1303,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
// This way, upon encountering an epoch change, the proposer from the // This way, upon encountering an epoch change, the proposer from the
// new set will be forced to wait until the next step to avoid sealing a // new set will be forced to wait until the next step to avoid sealing a
// block that breaks the invariant that the parent's step < the block's step. // block that breaks the invariant that the parent's step < the block's step.
self.can_propose.store(false, AtomicOrdering::SeqCst); self.step.can_propose.store(false, AtomicOrdering::SeqCst);
return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof)); return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof));
} }
} }

View File

@ -126,6 +126,8 @@ pub struct MinerOptions {
pub tx_queue_strategy: PrioritizationStrategy, pub tx_queue_strategy: PrioritizationStrategy,
/// Simple senders penalization. /// Simple senders penalization.
pub tx_queue_penalization: Penalization, pub tx_queue_penalization: Penalization,
/// Do we want to mark transactions recieved locally (e.g. RPC) as local if we don't have the sending account?
pub tx_queue_no_unfamiliar_locals: bool,
/// Do we refuse to accept service transactions even if sender is certified. /// Do we refuse to accept service transactions even if sender is certified.
pub refuse_service_transactions: bool, pub refuse_service_transactions: bool,
/// Transaction pool limits. /// Transaction pool limits.
@ -149,6 +151,7 @@ impl Default for MinerOptions {
infinite_pending_block: false, infinite_pending_block: false,
tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, tx_queue_strategy: PrioritizationStrategy::GasPriceOnly,
tx_queue_penalization: Penalization::Disabled, tx_queue_penalization: Penalization::Disabled,
tx_queue_no_unfamiliar_locals: false,
refuse_service_transactions: false, refuse_service_transactions: false,
pool_limits: pool::Options { pool_limits: pool::Options {
max_count: 8_192, max_count: 8_192,
@ -688,6 +691,20 @@ impl Miner {
// Return if we restarted // Return if we restarted
prepare_new prepare_new
} }
/// Prepare pending block, check whether sealing is needed, and then update sealing.
fn prepare_and_update_sealing<C: miner::BlockChainClient>(&self, chain: &C) {
use miner::MinerService;
// Make sure to do it after transaction is imported and lock is dropped.
// We need to create pending block and enable sealing.
if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) {
// If new block has not been prepared (means we already had one)
// or Engine might be able to seal internally,
// we need to update sealing.
self.update_sealing(chain);
}
}
} }
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5;
@ -754,12 +771,12 @@ impl miner::MinerService for Miner {
transactions.into_iter().map(pool::verifier::Transaction::Unverified).collect(), transactions.into_iter().map(pool::verifier::Transaction::Unverified).collect(),
); );
// --------------------------------------------------------------------------
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
if !results.is_empty() && self.options.reseal_on_external_tx && self.sealing.lock().reseal_allowed() { if !results.is_empty() && self.options.reseal_on_external_tx && self.sealing.lock().reseal_allowed() {
// -------------------------------------------------------------------------- self.prepare_and_update_sealing(chain);
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.update_sealing(chain);
} }
results results
@ -768,8 +785,9 @@ impl miner::MinerService for Miner {
fn import_own_transaction<C: miner::BlockChainClient>( fn import_own_transaction<C: miner::BlockChainClient>(
&self, &self,
chain: &C, chain: &C,
pending: PendingTransaction, pending: PendingTransaction
) -> Result<(), transaction::Error> { ) -> Result<(), transaction::Error> {
// note: you may want to use `import_claimed_local_transaction` instead of this one.
trace!(target: "own_tx", "Importing transaction: {:?}", pending); trace!(target: "own_tx", "Importing transaction: {:?}", pending);
@ -784,19 +802,34 @@ impl miner::MinerService for Miner {
// | Make sure to release the locks before calling that method. | // | Make sure to release the locks before calling that method. |
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() { if imported.is_ok() && self.options.reseal_on_own_tx && self.sealing.lock().reseal_allowed() {
// Make sure to do it after transaction is imported and lock is droped. self.prepare_and_update_sealing(chain);
// We need to create pending block and enable sealing.
if self.engine.seals_internally().unwrap_or(false) || !self.prepare_pending_block(chain) {
// If new block has not been prepared (means we already had one)
// or Engine might be able to seal internally,
// we need to update sealing.
self.update_sealing(chain);
}
} }
imported imported
} }
fn import_claimed_local_transaction<C: miner::BlockChainClient>(
&self,
chain: &C,
pending: PendingTransaction,
trusted: bool
) -> Result<(), transaction::Error> {
// treat the tx as local if the option is enabled, or if we have the account
let sender = pending.sender();
let treat_as_local = trusted
|| !self.options.tx_queue_no_unfamiliar_locals
|| self.accounts.as_ref().map(|accts| accts.has_account(sender)).unwrap_or(false);
if treat_as_local {
self.import_own_transaction(chain, pending)
} else {
// We want to replicate behaviour for external transactions if we're not going to treat
// this as local. This is important with regards to sealing blocks
self.import_external_transactions(chain, vec![pending.transaction.into()])
.pop().expect("one result per tx, as in `import_own_transaction`")
}
}
fn local_transactions(&self) -> BTreeMap<H256, pool::local_transactions::Status> { fn local_transactions(&self) -> BTreeMap<H256, pool::local_transactions::Status> {
self.transaction_queue.local_transactions() self.transaction_queue.local_transactions()
} }
@ -1133,6 +1166,7 @@ mod tests {
infinite_pending_block: false, infinite_pending_block: false,
tx_queue_penalization: Penalization::Disabled, tx_queue_penalization: Penalization::Disabled,
tx_queue_strategy: PrioritizationStrategy::GasPriceOnly, tx_queue_strategy: PrioritizationStrategy::GasPriceOnly,
tx_queue_no_unfamiliar_locals: false,
refuse_service_transactions: false, refuse_service_transactions: false,
pool_limits: Default::default(), pool_limits: Default::default(),
pool_verification_options: pool::verifier::Options { pool_verification_options: pool::verifier::Options {
@ -1147,8 +1181,10 @@ mod tests {
) )
} }
const TEST_CHAIN_ID: u64 = 2;
fn transaction() -> SignedTransaction { fn transaction() -> SignedTransaction {
transaction_with_chain_id(2) transaction_with_chain_id(TEST_CHAIN_ID)
} }
fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction { fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction {
@ -1222,6 +1258,53 @@ mod tests {
assert_eq!(miner.ready_transactions(&client).len(), 1); assert_eq!(miner.ready_transactions(&client).len(), 1);
} }
#[test]
fn should_treat_unfamiliar_locals_selectively() {
// given
let keypair = Random.generate().unwrap();
let client = TestBlockChainClient::default();
let account_provider = AccountProvider::transient_provider();
account_provider.insert_account(keypair.secret().clone(), "").expect("can add accounts to the provider we just created");
let miner = Miner::new(
MinerOptions {
tx_queue_no_unfamiliar_locals: true,
..miner().options
},
GasPricer::new_fixed(0u64.into()),
&Spec::new_test(),
Some(Arc::new(account_provider)),
);
let transaction = transaction();
let best_block = 0;
// when
// This transaction should not be marked as local because our account_provider doesn't have the sender
let res = miner.import_claimed_local_transaction(&client, PendingTransaction::new(transaction.clone(), None), false);
// then
// Check the same conditions as `should_import_external_transaction` first. Behaviour should be identical.
// That is: it's treated as though we added it through `import_external_transactions`
assert_eq!(res.unwrap(), ());
assert_eq!(miner.pending_transactions(best_block), None);
assert_eq!(miner.pending_receipts(best_block), None);
assert_eq!(miner.ready_transactions(&client).len(), 0);
assert!(miner.prepare_pending_block(&client));
assert_eq!(miner.ready_transactions(&client).len(), 1);
// when - 2nd part: create a local transaction from account_provider.
// Borrow the transaction used before & sign with our generated keypair.
let local_transaction = transaction.deconstruct().0.as_unsigned().clone().sign(keypair.secret(), Some(TEST_CHAIN_ID));
let res2 = miner.import_claimed_local_transaction(&client, PendingTransaction::new(local_transaction, None), false);
// then - 2nd part: we add on the results from the last pending block.
// This is borrowed from `should_make_pending_block_when_importing_own_transaction` and slightly modified.
assert_eq!(res2.unwrap(), ());
assert_eq!(miner.pending_transactions(best_block).unwrap().len(), 2);
assert_eq!(miner.pending_receipts(best_block).unwrap().len(), 2);
assert_eq!(miner.ready_transactions(&client).len(), 2);
assert!(!miner.prepare_pending_block(&client));
}
#[test] #[test]
fn should_not_seal_unless_enabled() { fn should_not_seal_unless_enabled() {
let miner = miner(); let miner = miner();

View File

@ -139,6 +139,12 @@ pub trait MinerService : Send + Sync {
-> Result<(), transaction::Error> -> Result<(), transaction::Error>
where C: BlockChainClient; where C: BlockChainClient;
/// Imports transactions from potentially external sources, with behaviour determined
/// by the config flag `tx_queue_allow_unfamiliar_locals`
fn import_claimed_local_transaction<C>(&self, chain: &C, transaction: PendingTransaction, trusted: bool)
-> Result<(), transaction::Error>
where C: BlockChainClient;
/// Removes transaction from the pool. /// Removes transaction from the pool.
/// ///
/// Attempts to "cancel" a transaction. If it was not propagated yet (or not accepted by other peers) /// Attempts to "cancel" a transaction. If it was not propagated yet (or not accepted by other peers)

View File

@ -124,7 +124,7 @@ impl<'a, C: 'a> pool::client::Client for PoolClient<'a, C> where
pool::client::AccountDetails { pool::client::AccountDetails {
nonce: self.cached_nonces.account_nonce(address), nonce: self.cached_nonces.account_nonce(address),
balance: self.chain.latest_balance(address), balance: self.chain.latest_balance(address),
is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address).unwrap_or(false)), is_local: self.accounts.map_or(false, |accounts| accounts.has_account(*address)),
} }
} }

View File

@ -215,7 +215,7 @@ fn fixed_to_contract_only() {
secret!("dog42"), secret!("dog42"),
]); ]);
assert!(provider.has_account(*RICH_ADDR).unwrap()); assert!(provider.has_account(*RICH_ADDR));
let client = make_chain(provider, 3, vec![ let client = make_chain(provider, 3, vec![
Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]), Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]),
@ -248,7 +248,7 @@ fn fixed_to_contract_to_contract() {
secret!("dog42"), secret!("dog42"),
]); ]);
assert!(provider.has_account(*RICH_ADDR).unwrap()); assert!(provider.has_account(*RICH_ADDR));
let client = make_chain(provider, 3, vec![ let client = make_chain(provider, 3, vec![
Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]), Transition::Manual(3, vec![addrs[2], addrs[3], addrs[5], addrs[7]]),

View File

@ -17,14 +17,14 @@
//! Watcher for snapshot-related chain events. //! Watcher for snapshot-related chain events.
use parking_lot::Mutex; use parking_lot::Mutex;
use client::{BlockInfo, Client, ChainNotify, ClientIoMessage}; use client::{BlockInfo, Client, ChainNotify, ChainRoute, ClientIoMessage};
use ids::BlockId; use ids::BlockId;
use io::IoChannel; use io::IoChannel;
use ethereum_types::H256; use ethereum_types::H256;
use bytes::Bytes; use bytes::Bytes;
use std::sync::Arc; use std::{sync::Arc, time::Duration};
// helper trait for transforming hashes to numbers and checking if syncing. // helper trait for transforming hashes to numbers and checking if syncing.
trait Oracle: Send + Sync { trait Oracle: Send + Sync {
@ -103,11 +103,10 @@ impl ChainNotify for Watcher {
&self, &self,
imported: Vec<H256>, imported: Vec<H256>,
_: Vec<H256>, _: Vec<H256>,
_: Vec<H256>, _: ChainRoute,
_: Vec<H256>,
_: Vec<H256>, _: Vec<H256>,
_: Vec<Bytes>, _: Vec<Bytes>,
_duration: u64) _duration: Duration)
{ {
if self.oracle.is_major_importing() { return } if self.oracle.is_major_importing() { return }
@ -131,11 +130,12 @@ impl ChainNotify for Watcher {
mod tests { mod tests {
use super::{Broadcast, Oracle, Watcher}; use super::{Broadcast, Oracle, Watcher};
use client::ChainNotify; use client::{ChainNotify, ChainRoute};
use ethereum_types::{H256, U256}; use ethereum_types::{H256, U256};
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration;
struct TestOracle(HashMap<H256, u64>); struct TestOracle(HashMap<H256, u64>);
@ -158,6 +158,8 @@ mod tests {
// helper harness for tests which expect a notification. // helper harness for tests which expect a notification.
fn harness(numbers: Vec<u64>, period: u64, history: u64, expected: Option<u64>) { fn harness(numbers: Vec<u64>, period: u64, history: u64, expected: Option<u64>) {
const DURATION_ZERO: Duration = Duration::from_millis(0);
let hashes: Vec<_> = numbers.clone().into_iter().map(|x| H256::from(U256::from(x))).collect(); let hashes: Vec<_> = numbers.clone().into_iter().map(|x| H256::from(U256::from(x))).collect();
let map = hashes.clone().into_iter().zip(numbers).collect(); let map = hashes.clone().into_iter().zip(numbers).collect();
@ -171,11 +173,10 @@ mod tests {
watcher.new_blocks( watcher.new_blocks(
hashes, hashes,
vec![], vec![],
ChainRoute::default(),
vec![], vec![],
vec![], vec![],
vec![], DURATION_ZERO,
vec![],
0,
); );
} }

View File

@ -39,10 +39,10 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view {
/// Returns a new instance replacing existing rlp with new rlp, maintaining debug info /// Returns a new instance replacing existing rlp with new rlp, maintaining debug info
fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self { fn new_from_rlp(&self, rlp: Rlp<'a>) -> Self {
ViewRlp { ViewRlp {
rlp, rlp,
file: self.file, file: self.file,
line: self.line line: self.line
} }
} }
@ -53,7 +53,12 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view {
} }
fn expect_valid_rlp<T>(&self, r: Result<T, DecoderError>) -> T { fn expect_valid_rlp<T>(&self, r: Result<T, DecoderError>) -> T {
r.expect(&format!("View rlp is trusted and should be valid. Constructed in {} on line {}", self.file, self.line)) r.unwrap_or_else(|e| panic!(
"View rlp is trusted and should be valid. Constructed in {} on line {}: {}",
self.file,
self.line,
e
))
} }
/// Returns rlp at the given index, panics if no rlp at that index /// Returns rlp at the given index, panics if no rlp at that index
@ -75,7 +80,7 @@ impl<'a, 'view> ViewRlp<'a> where 'a : 'view {
/// Returns decoded value at the given index, panics not present or valid at that index /// Returns decoded value at the given index, panics not present or valid at that index
pub fn val_at<T>(&self, index: usize) -> T where T : Decodable { pub fn val_at<T>(&self, index: usize) -> T where T : Decodable {
self.expect_valid_rlp(self.rlp.val_at(index)) self.expect_valid_rlp(self.rlp.val_at(index))
} }
/// Returns decoded list of values, panics if rlp is invalid /// Returns decoded list of values, panics if rlp is invalid
pub fn list_at<T>(&self, index: usize) -> Vec<T> where T: Decodable { pub fn list_at<T>(&self, index: usize) -> Vec<T> where T: Decodable {

View File

@ -25,7 +25,7 @@ use network::{NetworkProtocolHandler, NetworkContext, HostInfo, PeerId, Protocol
use ethereum_types::{H256, H512, U256}; use ethereum_types::{H256, H512, U256};
use io::{TimerToken}; use io::{TimerToken};
use ethcore::ethstore::ethkey::Secret; use ethcore::ethstore::ethkey::Secret;
use ethcore::client::{BlockChainClient, ChainNotify, ChainMessageType}; use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainMessageType};
use ethcore::snapshot::SnapshotService; use ethcore::snapshot::SnapshotService;
use ethcore::header::BlockNumber; use ethcore::header::BlockNumber;
use sync_io::NetSyncIo; use sync_io::NetSyncIo;
@ -410,11 +410,10 @@ impl ChainNotify for EthSync {
fn new_blocks(&self, fn new_blocks(&self,
imported: Vec<H256>, imported: Vec<H256>,
invalid: Vec<H256>, invalid: Vec<H256>,
enacted: Vec<H256>, route: ChainRoute,
retracted: Vec<H256>,
sealed: Vec<H256>, sealed: Vec<H256>,
proposed: Vec<Bytes>, proposed: Vec<Bytes>,
_duration: u64) _duration: Duration)
{ {
use light::net::Announcement; use light::net::Announcement;
@ -425,8 +424,8 @@ impl ChainNotify for EthSync {
&mut sync_io, &mut sync_io,
&imported, &imported,
&invalid, &invalid,
&enacted, route.enacted(),
&retracted, route.retracted(),
&sealed, &sealed,
&proposed); &proposed);
}); });
@ -453,7 +452,7 @@ impl ChainNotify for EthSync {
fn start(&self) { fn start(&self) {
match self.network.start().map_err(Into::into) { match self.network.start().map_err(Into::into) {
Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => warn!("Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")),
Err(err) => warn!("Error starting network: {}", err), Err(err) => warn!("Error starting network: {}", err),
_ => {}, _ => {},
} }
@ -626,7 +625,7 @@ impl NetworkConfiguration {
config_path: self.config_path, config_path: self.config_path,
net_config_path: self.net_config_path, net_config_path: self.net_config_path,
listen_address: match self.listen_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, listen_address: match self.listen_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) },
public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) }, public_address: match self.public_address { None => None, Some(addr) => Some(SocketAddr::from_str(&addr)?) },
udp_port: self.udp_port, udp_port: self.udp_port,
nat_enabled: self.nat_enabled, nat_enabled: self.nat_enabled,
discovery_enabled: self.discovery_enabled, discovery_enabled: self.discovery_enabled,

View File

@ -133,7 +133,7 @@ impl SyncSupplier {
let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers); let max_count = cmp::min(MAX_HEADERS_TO_SEND, max_headers);
let mut count = 0; let mut count = 0;
let mut data = Bytes::new(); let mut data = Bytes::new();
let inc = (skip + 1) as BlockNumber; let inc = skip.saturating_add(1) as BlockNumber;
let overlay = io.chain_overlay().read(); let overlay = io.chain_overlay().read();
// We are checking the `overlay` as well since it's where the ForkBlock // We are checking the `overlay` as well since it's where the ForkBlock
@ -155,9 +155,9 @@ impl SyncSupplier {
if number <= inc || number == 0 { if number <= inc || number == 0 {
break; break;
} }
number -= inc; number = number.saturating_sub(inc);
} else { } else {
number += inc; number = number.saturating_add(inc);
} }
} }
let mut rlp = RlpStream::new_list(count as usize); let mut rlp = RlpStream::new_list(count as usize);

View File

@ -16,13 +16,14 @@
use std::collections::{VecDeque, HashSet, HashMap}; use std::collections::{VecDeque, HashSet, HashMap};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
use ethereum_types::H256; use ethereum_types::H256;
use parking_lot::{RwLock, Mutex}; use parking_lot::{RwLock, Mutex};
use bytes::Bytes; use bytes::Bytes;
use network::{self, PeerId, ProtocolId, PacketId, SessionInfo}; use network::{self, PeerId, ProtocolId, PacketId, SessionInfo};
use tests::snapshot::*; use tests::snapshot::*;
use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient, use ethcore::client::{TestBlockChainClient, BlockChainClient, Client as EthcoreClient,
ClientConfig, ChainNotify, ChainMessageType, ClientIoMessage}; ClientConfig, ChainNotify, ChainRoute, ChainMessageType, ClientIoMessage};
use ethcore::header::BlockNumber; use ethcore::header::BlockNumber;
use ethcore::snapshot::SnapshotService; use ethcore::snapshot::SnapshotService;
use ethcore::spec::Spec; use ethcore::spec::Spec;
@ -532,12 +533,13 @@ impl ChainNotify for EthPeer<EthcoreClient> {
fn new_blocks(&self, fn new_blocks(&self,
imported: Vec<H256>, imported: Vec<H256>,
invalid: Vec<H256>, invalid: Vec<H256>,
enacted: Vec<H256>, route: ChainRoute,
retracted: Vec<H256>,
sealed: Vec<H256>, sealed: Vec<H256>,
proposed: Vec<Bytes>, proposed: Vec<Bytes>,
_duration: u64) _duration: Duration)
{ {
let (enacted, retracted) = route.into_enacted_retracted();
self.new_blocks_queue.write().push_back(NewBlockMessage { self.new_blocks_queue.write().push_back(NewBlockMessage {
imported, imported,
invalid, invalid,

View File

@ -27,7 +27,6 @@ linked-hash-map = "0.5"
log = "0.3" log = "0.3"
parking_lot = "0.5" parking_lot = "0.5"
price-info = { path = "../price-info" } price-info = { path = "../price-info" }
rayon = "1.0"
rlp = { path = "../util/rlp" } rlp = { path = "../util/rlp" }
trace-time = { path = "../util/trace-time" } trace-time = { path = "../util/trace-time" }
transaction-pool = { path = "../transaction-pool" } transaction-pool = { path = "../transaction-pool" }

View File

@ -29,7 +29,6 @@ extern crate keccak_hash as hash;
extern crate linked_hash_map; extern crate linked_hash_map;
extern crate parking_lot; extern crate parking_lot;
extern crate price_info; extern crate price_info;
extern crate rayon;
extern crate rlp; extern crate rlp;
extern crate trace_time; extern crate trace_time;
extern crate transaction_pool as txpool; extern crate transaction_pool as txpool;

View File

@ -23,7 +23,6 @@ use std::collections::BTreeMap;
use ethereum_types::{H256, U256, Address}; use ethereum_types::{H256, U256, Address};
use parking_lot::RwLock; use parking_lot::RwLock;
use rayon::prelude::*;
use transaction; use transaction;
use txpool::{self, Verifier}; use txpool::{self, Verifier};
@ -179,8 +178,14 @@ impl TransactionQueue {
let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone()); let verifier = verifier::Verifier::new(client, options, self.insertion_id.clone());
let results = transactions let results = transactions
.into_par_iter() .into_iter()
.map(|transaction| verifier.verify_transaction(transaction)) .map(|transaction| {
if self.pool.read().find(&transaction.hash()).is_some() {
bail!(transaction::Error::AlreadyImported)
}
verifier.verify_transaction(transaction)
})
.map(|result| result.and_then(|verified| { .map(|result| result.and_then(|verified| {
self.pool.write().import(verified) self.pool.write().import(verified)
.map(|_imported| ()) .map(|_imported| ())

View File

@ -14,6 +14,8 @@
// 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 std::sync::{atomic, Arc};
use ethereum_types::{U256, H256, Address}; use ethereum_types::{U256, H256, Address};
use rlp::Rlp; use rlp::Rlp;
use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction}; use transaction::{self, Transaction, SignedTransaction, UnverifiedTransaction};
@ -25,6 +27,7 @@ const MAX_TRANSACTION_SIZE: usize = 15 * 1024;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TestClient { pub struct TestClient {
verification_invoked: Arc<atomic::AtomicBool>,
account_details: AccountDetails, account_details: AccountDetails,
gas_required: U256, gas_required: U256,
is_service_transaction: bool, is_service_transaction: bool,
@ -35,6 +38,7 @@ pub struct TestClient {
impl Default for TestClient { impl Default for TestClient {
fn default() -> Self { fn default() -> Self {
TestClient { TestClient {
verification_invoked: Default::default(),
account_details: AccountDetails { account_details: AccountDetails {
nonce: 123.into(), nonce: 123.into(),
balance: 63_100.into(), balance: 63_100.into(),
@ -88,6 +92,10 @@ impl TestClient {
insertion_id: 1, insertion_id: 1,
} }
} }
pub fn was_verification_triggered(&self) -> bool {
self.verification_invoked.load(atomic::Ordering::SeqCst)
}
} }
impl pool::client::Client for TestClient { impl pool::client::Client for TestClient {
@ -98,6 +106,7 @@ impl pool::client::Client for TestClient {
fn verify_transaction(&self, tx: UnverifiedTransaction) fn verify_transaction(&self, tx: UnverifiedTransaction)
-> Result<SignedTransaction, transaction::Error> -> Result<SignedTransaction, transaction::Error>
{ {
self.verification_invoked.store(true, atomic::Ordering::SeqCst);
Ok(SignedTransaction::new(tx)?) Ok(SignedTransaction::new(tx)?)
} }

View File

@ -798,3 +798,37 @@ fn should_include_local_transaction_to_a_full_pool() {
// then // then
assert_eq!(txq.status().status.transaction_count, 1); assert_eq!(txq.status().status.transaction_count, 1);
} }
#[test]
fn should_avoid_verifying_transaction_already_in_pool() {
// given
let txq = TransactionQueue::new(
txpool::Options {
max_count: 1,
max_per_sender: 2,
max_mem_usage: 50
},
verifier::Options {
minimal_gas_price: 1.into(),
block_gas_limit: 1_000_000.into(),
tx_gas_limit: 1_000_000.into(),
},
PrioritizationStrategy::GasPriceOnly,
);
let client = TestClient::new();
let tx1 = Tx::default().signed().unverified();
let res = txq.import(client.clone(), vec![tx1.clone()]);
assert_eq!(res, vec![Ok(())]);
assert_eq!(txq.status().status.transaction_count, 1);
assert!(client.was_verification_triggered());
// when
let client = TestClient::new();
let res = txq.import(client.clone(), vec![tx1]);
assert_eq!(res, vec![Err(transaction::Error::AlreadyImported)]);
assert!(!client.was_verification_triggered());
// then
assert_eq!(txq.status().status.transaction_count, 1);
}

View File

@ -57,6 +57,7 @@ impl Default for Options {
} }
/// Transaction to verify. /// Transaction to verify.
#[cfg_attr(test, derive(Clone))]
pub enum Transaction { pub enum Transaction {
/// Fresh, never verified transaction. /// Fresh, never verified transaction.
/// ///
@ -75,7 +76,8 @@ pub enum Transaction {
} }
impl Transaction { impl Transaction {
fn hash(&self) -> H256 { /// Return transaction hash
pub fn hash(&self) -> H256 {
match *self { match *self {
Transaction::Unverified(ref tx) => tx.hash(), Transaction::Unverified(ref tx) => tx.hash(),
Transaction::Retracted(ref tx) => tx.hash(), Transaction::Retracted(ref tx) => tx.hash(),

View File

@ -665,6 +665,10 @@ usage! {
"--remove-solved", "--remove-solved",
"Move solved blocks from the work package queue instead of cloning them. This gives a slightly faster import speed, but means that extra solutions submitted for the same work package will go unused.", "Move solved blocks from the work package queue instead of cloning them. This gives a slightly faster import speed, but means that extra solutions submitted for the same work package will go unused.",
FLAG flag_tx_queue_no_unfamiliar_locals: (bool) = false, or |c: &Config| c.mining.as_ref()?.tx_queue_no_unfamiliar_locals.clone(),
"--tx-queue-no-unfamiliar-locals",
"Transactions recieved via local means (RPC, WS, etc) will be treated as external if the sending account is unknown.",
FLAG flag_refuse_service_transactions: (bool) = false, or |c: &Config| c.mining.as_ref()?.refuse_service_transactions.clone(), FLAG flag_refuse_service_transactions: (bool) = false, or |c: &Config| c.mining.as_ref()?.refuse_service_transactions.clone(),
"--refuse-service-transactions", "--refuse-service-transactions",
"Always refuse service transactions.", "Always refuse service transactions.",
@ -1241,6 +1245,7 @@ struct Mining {
tx_queue_strategy: Option<String>, tx_queue_strategy: Option<String>,
tx_queue_ban_count: Option<u16>, tx_queue_ban_count: Option<u16>,
tx_queue_ban_time: Option<u16>, tx_queue_ban_time: Option<u16>,
tx_queue_no_unfamiliar_locals: Option<bool>,
remove_solved: Option<bool>, remove_solved: Option<bool>,
notify_work: Option<Vec<String>>, notify_work: Option<Vec<String>>,
refuse_service_transactions: Option<bool>, refuse_service_transactions: Option<bool>,
@ -1657,6 +1662,7 @@ mod tests {
arg_gas_floor_target: "4700000".into(), arg_gas_floor_target: "4700000".into(),
arg_gas_cap: "6283184".into(), arg_gas_cap: "6283184".into(),
arg_extra_data: Some("Parity".into()), arg_extra_data: Some("Parity".into()),
flag_tx_queue_no_unfamiliar_locals: false,
arg_tx_queue_size: 8192usize, arg_tx_queue_size: 8192usize,
arg_tx_queue_per_sender: None, arg_tx_queue_per_sender: None,
arg_tx_queue_mem_limit: 4u32, arg_tx_queue_mem_limit: 4u32,
@ -1922,6 +1928,7 @@ mod tests {
tx_queue_strategy: None, tx_queue_strategy: None,
tx_queue_ban_count: None, tx_queue_ban_count: None,
tx_queue_ban_time: None, tx_queue_ban_time: None,
tx_queue_no_unfamiliar_locals: None,
tx_gas_limit: None, tx_gas_limit: None,
tx_time_limit: None, tx_time_limit: None,
extra_data: None, extra_data: None,

View File

@ -133,6 +133,7 @@ tx_queue_ban_count = 1
tx_queue_ban_time = 180 #s tx_queue_ban_time = 180 #s
tx_gas_limit = "6283184" tx_gas_limit = "6283184"
tx_time_limit = 100 #ms tx_time_limit = 100 #ms
tx_queue_no_unfamiliar_locals = false
extra_data = "Parity" extra_data = "Parity"
remove_solved = false remove_solved = false
notify_work = ["http://localhost:3001"] notify_work = ["http://localhost:3001"]

View File

@ -549,6 +549,7 @@ impl Configuration {
tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?, tx_queue_penalization: to_queue_penalization(self.args.arg_tx_time_limit)?,
tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?, tx_queue_strategy: to_queue_strategy(&self.args.arg_tx_queue_strategy)?,
tx_queue_no_unfamiliar_locals: self.args.flag_tx_queue_no_unfamiliar_locals,
refuse_service_transactions: self.args.flag_refuse_service_transactions, refuse_service_transactions: self.args.flag_refuse_service_transactions,
pool_limits: self.pool_limits()?, pool_limits: self.pool_limits()?,

View File

@ -25,7 +25,7 @@ use std::time::{Instant, Duration};
use atty; use atty;
use ethcore::client::{ use ethcore::client::{
BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo,
BlockQueueInfo, ChainNotify, ClientReport, Client, ClientIoMessage BlockQueueInfo, ChainNotify, ChainRoute, ClientReport, Client, ClientIoMessage
}; };
use ethcore::header::BlockNumber; use ethcore::header::BlockNumber;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS}; use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
@ -360,7 +360,7 @@ impl<T: InformantData> Informant<T> {
} }
impl ChainNotify for Informant<FullNodeInformantData> { impl ChainNotify for Informant<FullNodeInformantData> {
fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, duration: u64) { fn new_blocks(&self, imported: Vec<H256>, _invalid: Vec<H256>, _route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, duration: Duration) {
let mut last_import = self.last_import.lock(); let mut last_import = self.last_import.lock();
let client = &self.target.client; let client = &self.target.client;
@ -382,7 +382,7 @@ impl ChainNotify for Informant<FullNodeInformantData> {
Colour::White.bold().paint(format!("{}", header_view.hash())), Colour::White.bold().paint(format!("{}", header_view.hash())),
Colour::Yellow.bold().paint(format!("{}", block.transactions_count())), Colour::Yellow.bold().paint(format!("{}", block.transactions_count())),
Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)), Colour::Yellow.bold().paint(format!("{:.2}", header_view.gas_used().low_u64() as f32 / 1000000f32)),
Colour::Purple.bold().paint(format!("{:.2}", duration as f32 / 1000000f32)), Colour::Purple.bold().paint(format!("{}", duration.as_milliseconds())),
Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)), Colour::Blue.bold().paint(format!("{:.2}", size as f32 / 1024f32)),
if skipped > 0 { if skipped > 0 {
format!(" + another {} block(s) containing {} tx(s)", format!(" + another {} block(s) containing {} tx(s)",

View File

@ -562,7 +562,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
let engine_signer = cmd.miner_extras.engine_signer; let engine_signer = cmd.miner_extras.engine_signer;
if engine_signer != Default::default() { if engine_signer != Default::default() {
// Check if engine signer exists // Check if engine signer exists
if !account_provider.has_account(engine_signer).unwrap_or(false) { if !account_provider.has_account(engine_signer) {
return Err(format!("Consensus signer account not found for the current chain. {}", build_create_account_hint(&cmd.spec, &cmd.dirs.keys))); return Err(format!("Consensus signer account not found for the current chain. {}", build_create_account_hint(&cmd.spec, &cmd.dirs.keys)));
} }
@ -1067,7 +1067,7 @@ fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str,
for a in cfg.unlocked_accounts { for a in cfg.unlocked_accounts {
// Check if the account exists // Check if the account exists
if !account_provider.has_account(a).unwrap_or(false) { if !account_provider.has_account(a) {
return Err(format!("Account {} not found for the current chain. {}", a, build_create_account_hint(spec, &dirs.keys))); return Err(format!("Account {} not found for the current chain. {}", a, build_create_account_hint(spec, &dirs.keys)));
} }
@ -1092,7 +1092,7 @@ fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str,
fn insert_dev_account(account_provider: &AccountProvider) { fn insert_dev_account(account_provider: &AccountProvider) {
let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into(); let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into();
let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed"); let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed");
if let Ok(false) = account_provider.has_account(dev_account.address()) { if !account_provider.has_account(dev_account.address()) {
match account_provider.insert_account(secret, "") { match account_provider.insert_account(secret, "") {
Err(e) => warn!("Unable to add development account: {}", e), Err(e) => warn!("Unable to add development account: {}", e),
Ok(address) => { Ok(address) => {

View File

@ -144,7 +144,7 @@ mod server {
KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)), KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)),
Some(NodeSecretKey::KeyStore(account)) => { Some(NodeSecretKey::KeyStore(account)) => {
// Check if account exists // Check if account exists
if !deps.account_provider.has_account(account.clone()).unwrap_or(false) { if !deps.account_provider.has_account(account.clone()) {
return Err(format!("Account {} passed as secret store node key is not found", account)); return Err(format!("Account {} passed as secret store node key is not found", account));
} }

View File

@ -123,10 +123,13 @@ impl<C: miner::BlockChainClient, M: MinerService> FullDispatcher<C, M> {
} }
/// Imports transaction to the miner's queue. /// Imports transaction to the miner's queue.
pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: PendingTransaction) -> Result<H256> { pub fn dispatch_transaction(client: &C, miner: &M, signed_transaction: PendingTransaction, trusted: bool) -> Result<H256> {
let hash = signed_transaction.transaction.hash(); let hash = signed_transaction.transaction.hash();
miner.import_own_transaction(client, signed_transaction) // use `import_claimed_local_transaction` so we can decide (based on config flags) if we want to treat
// it as local or not. Nodes with public RPC interfaces will want these transactions to be treated like
// external transactions.
miner.import_claimed_local_transaction(client, signed_transaction, trusted)
.map_err(errors::transaction) .map_err(errors::transaction)
.map(|_| hash) .map(|_| hash)
} }
@ -180,7 +183,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
} }
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256> { fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256> {
Self::dispatch_transaction(&*self.client, &*self.miner, signed_transaction) Self::dispatch_transaction(&*self.client, &*self.miner, signed_transaction, true)
} }
} }

View File

@ -45,7 +45,7 @@ pub use self::requests::{
TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest, TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest,
}; };
pub use self::signing_queue::{ pub use self::signing_queue::{
ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult, ConfirmationsQueue, ConfirmationReceiver, ConfirmationResult, ConfirmationSender,
SigningQueue, QueueEvent, DefaultAccount, SigningQueue, QueueEvent, DefaultAccount,
QUEUE_LIMIT as SIGNING_QUEUE_LIMIT, QUEUE_LIMIT as SIGNING_QUEUE_LIMIT,
}; };

View File

@ -13,8 +13,8 @@ pub enum PollFilter {
Block(BlockNumber), Block(BlockNumber),
/// Hashes of all transactions which client was notified about. /// Hashes of all transactions which client was notified about.
PendingTransaction(Vec<H256>), PendingTransaction(Vec<H256>),
/// Number of From block number, pending logs and log filter itself. /// Number of From block number, last seen block hash, pending logs and log filter itself.
Logs(BlockNumber, HashSet<Log>, Filter) Logs(BlockNumber, Option<H256>, HashSet<Log>, Filter)
} }
/// Returns only last `n` logs /// Returns only last `n` logs

View File

@ -75,16 +75,17 @@ pub trait SigningQueue: Send + Sync {
/// `ConfirmationReceiver` is a `Future` awaiting for resolution of the given request. /// `ConfirmationReceiver` is a `Future` awaiting for resolution of the given request.
fn add_request(&self, request: ConfirmationPayload, origin: Origin) -> Result<(U256, ConfirmationReceiver), QueueAddError>; fn add_request(&self, request: ConfirmationPayload, origin: Origin) -> Result<(U256, ConfirmationReceiver), QueueAddError>;
/// Removes a request from the queue.
/// Notifies possible token holders that request was rejected. /// Notifies possible token holders that request was rejected.
fn request_rejected(&self, id: U256) -> Option<ConfirmationRequest>; fn request_rejected(&self, sender: ConfirmationSender) -> Option<ConfirmationRequest>;
/// Removes a request from the queue.
/// Notifies possible token holders that request was confirmed and given hash was assigned. /// Notifies possible token holders that request was confirmed and given hash was assigned.
fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option<ConfirmationRequest>; fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option<ConfirmationRequest>;
/// Returns a request if it is contained in the queue. /// Put a request taken from `SigningQueue::take` back to the queue.
fn peek(&self, id: &U256) -> Option<ConfirmationRequest>; fn request_untouched(&self, sender: ConfirmationSender);
/// Returns and removes a request if it is contained in the queue.
fn take(&self, id: &U256) -> Option<ConfirmationSender>;
/// Return copy of all the requests in the queue. /// Return copy of all the requests in the queue.
fn requests(&self) -> Vec<ConfirmationRequest>; fn requests(&self) -> Vec<ConfirmationRequest>;
@ -96,9 +97,12 @@ pub trait SigningQueue: Send + Sync {
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
} }
struct ConfirmationSender { /// Confirmation request information with result notifier.
pub struct ConfirmationSender {
/// Confirmation request information.
pub request: ConfirmationRequest,
sender: oneshot::Sender<ConfirmationResult>, sender: oneshot::Sender<ConfirmationResult>,
request: ConfirmationRequest,
} }
/// Receiving end of the Confirmation channel; can be used as a `Future` to await for `ConfirmationRequest` /// Receiving end of the Confirmation channel; can be used as a `Future` to await for `ConfirmationRequest`
@ -122,36 +126,29 @@ impl ConfirmationsQueue {
/// Notifies consumer that the communcation is over. /// Notifies consumer that the communcation is over.
/// No more events will be sent after this function is invoked. /// No more events will be sent after this function is invoked.
pub fn finish(&self) { pub fn finish(&self) {
self.notify(QueueEvent::Finish); self.notify_message(QueueEvent::Finish);
self.on_event.write().clear(); self.on_event.write().clear();
} }
/// Notifies receiver about the event happening in this queue. /// Notifies `ConfirmationReceiver` holder about the result given a request.
fn notify(&self, message: QueueEvent) { fn notify_result(&self, sender: ConfirmationSender, result: Option<ConfirmationResult>) -> Option<ConfirmationRequest> {
for listener in &*self.on_event.read() { // notify receiver about the event
listener(message.clone()) self.notify_message(result.clone().map_or_else(
} || QueueEvent::RequestRejected(sender.request.id),
|_| QueueEvent::RequestConfirmed(sender.request.id)
));
// notify confirmation receiver about resolution
let result = result.ok_or(errors::request_rejected());
sender.sender.send(result);
Some(sender.request)
} }
/// Removes requests from this queue and notifies `ConfirmationReceiver` holder about the result. /// Notifies receiver about the event happening in this queue.
/// Notifies also a receiver about that event. fn notify_message(&self, message: QueueEvent) {
fn remove(&self, id: U256, result: Option<ConfirmationResult>) -> Option<ConfirmationRequest> { for listener in &*self.on_event.read() {
let sender = self.queue.write().remove(&id); listener(message.clone())
if let Some(sender) = sender {
// notify receiver about the event
self.notify(result.clone().map_or_else(
|| QueueEvent::RequestRejected(id),
|_| QueueEvent::RequestConfirmed(id)
));
// notify confirmation receiver about resolution
let result = result.ok_or(errors::request_rejected());
sender.sender.send(result);
Some(sender.request)
} else {
None
} }
} }
} }
@ -193,22 +190,26 @@ impl SigningQueue for ConfirmationsQueue {
(id, receiver) (id, receiver)
}; };
// Notify listeners // Notify listeners
self.notify(QueueEvent::NewRequest(id)); self.notify_message(QueueEvent::NewRequest(id));
Ok(res) Ok(res)
} }
fn peek(&self, id: &U256) -> Option<ConfirmationRequest> { fn take(&self, id: &U256) -> Option<ConfirmationSender> {
self.queue.read().get(id).map(|sender| sender.request.clone()) self.queue.write().remove(id)
} }
fn request_rejected(&self, id: U256) -> Option<ConfirmationRequest> { fn request_rejected(&self, sender: ConfirmationSender) -> Option<ConfirmationRequest> {
debug!(target: "own_tx", "Signer: Request rejected ({:?}).", id); debug!(target: "own_tx", "Signer: Request rejected ({:?}).", sender.request.id);
self.remove(id, None) self.notify_result(sender, None)
} }
fn request_confirmed(&self, id: U256, result: ConfirmationResult) -> Option<ConfirmationRequest> { fn request_confirmed(&self, sender: ConfirmationSender, result: ConfirmationResult) -> Option<ConfirmationRequest> {
debug!(target: "own_tx", "Signer: Transaction confirmed ({:?}).", id); debug!(target: "own_tx", "Signer: Request confirmed ({:?}).", sender.request.id);
self.remove(id, Some(result)) self.notify_result(sender, Some(result))
}
fn request_untouched(&self, sender: ConfirmationSender) {
self.queue.write().insert(sender.request.id, sender);
} }
fn requests(&self) -> Vec<ConfirmationRequest> { fn requests(&self) -> Vec<ConfirmationRequest> {
@ -261,7 +262,8 @@ mod test {
// when // when
let (id, future) = queue.add_request(request, Default::default()).unwrap(); let (id, future) = queue.add_request(request, Default::default()).unwrap();
queue.request_confirmed(id, Ok(ConfirmationResponse::SendTransaction(1.into()))); let sender = queue.take(&id).unwrap();
queue.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(1.into())));
// then // then
let confirmation = future.wait().unwrap(); let confirmation = future.wait().unwrap();

View File

@ -824,6 +824,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
&*self.client, &*self.client,
&*self.miner, &*self.miner,
signed_transaction.into(), signed_transaction.into(),
false
) )
}) })
.map(Into::into) .map(Into::into)

View File

@ -39,7 +39,7 @@ pub trait Filterable {
fn best_block_number(&self) -> u64; fn best_block_number(&self) -> u64;
/// Get a block hash by block id. /// Get a block hash by block id.
fn block_hash(&self, id: BlockId) -> Option<RpcH256>; fn block_hash(&self, id: BlockId) -> Option<H256>;
/// pending transaction hashes at the given block. /// pending transaction hashes at the given block.
fn pending_transactions_hashes(&self) -> Vec<H256>; fn pending_transactions_hashes(&self) -> Vec<H256>;
@ -52,6 +52,9 @@ pub trait Filterable {
/// Get a reference to the poll manager. /// Get a reference to the poll manager.
fn polls(&self) -> &Mutex<PollManager<PollFilter>>; fn polls(&self) -> &Mutex<PollManager<PollFilter>>;
/// Get removed logs within route from the given block to the nearest canon block, not including the canon block. Also returns how many logs have been traversed.
fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec<Log>, u64);
} }
/// Eth filter rpc implementation for a full node. /// Eth filter rpc implementation for a full node.
@ -80,8 +83,8 @@ impl<C, M> Filterable for EthFilterClient<C, M> where
self.client.chain_info().best_block_number self.client.chain_info().best_block_number
} }
fn block_hash(&self, id: BlockId) -> Option<RpcH256> { fn block_hash(&self, id: BlockId) -> Option<H256> {
self.client.block_hash(id).map(Into::into) self.client.block_hash(id)
} }
fn pending_transactions_hashes(&self) -> Vec<H256> { fn pending_transactions_hashes(&self) -> Vec<H256> {
@ -100,6 +103,40 @@ impl<C, M> Filterable for EthFilterClient<C, M> where
} }
fn polls(&self) -> &Mutex<PollManager<PollFilter>> { &self.polls } fn polls(&self) -> &Mutex<PollManager<PollFilter>> { &self.polls }
fn removed_logs(&self, block_hash: H256, filter: &EthcoreFilter) -> (Vec<Log>, u64) {
let inner = || -> Option<Vec<H256>> {
let mut route = Vec::new();
let mut current_block_hash = block_hash;
let mut current_block_header = self.client.block_header(BlockId::Hash(current_block_hash))?;
while current_block_hash != self.client.block_hash(BlockId::Number(current_block_header.number()))? {
route.push(current_block_hash);
current_block_hash = current_block_header.parent_hash();
current_block_header = self.client.block_header(BlockId::Hash(current_block_hash))?;
}
Some(route)
};
let route = inner().unwrap_or_default();
let route_len = route.len() as u64;
(route.into_iter().flat_map(|block_hash| {
let mut filter = filter.clone();
filter.from_block = BlockId::Hash(block_hash);
filter.to_block = filter.from_block;
self.client.logs(filter).into_iter().map(|log| {
let mut log: Log = log.into();
log.log_type = "removed".into();
log.removed = true;
log
})
}).collect(), route_len)
}
} }
@ -108,7 +145,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
fn new_filter(&self, filter: Filter) -> Result<RpcU256> { fn new_filter(&self, filter: Filter) -> Result<RpcU256> {
let mut polls = self.polls().lock(); let mut polls = self.polls().lock();
let block_number = self.best_block_number(); let block_number = self.best_block_number();
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter)); let id = polls.create_poll(PollFilter::Logs(block_number, None, Default::default(), filter));
Ok(id.into()) Ok(id.into())
} }
@ -136,7 +173,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
let current_number = self.best_block_number() + 1; let current_number = self.best_block_number() + 1;
let hashes = (*block_number..current_number).into_iter() let hashes = (*block_number..current_number).into_iter()
.map(BlockId::Number) .map(BlockId::Number)
.filter_map(|id| self.block_hash(id)) .filter_map(|id| self.block_hash(id).map(Into::into))
.collect::<Vec<RpcH256>>(); .collect::<Vec<RpcH256>>();
*block_number = current_number; *block_number = current_number;
@ -166,7 +203,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
// return new hashes // return new hashes
Either::A(future::ok(FilterChanges::Hashes(new_hashes))) Either::A(future::ok(FilterChanges::Hashes(new_hashes)))
}, },
PollFilter::Logs(ref mut block_number, ref mut previous_logs, ref filter) => { PollFilter::Logs(ref mut block_number, ref mut last_block_hash, ref mut previous_logs, ref filter) => {
// retrive the current block number // retrive the current block number
let current_number = self.best_block_number(); let current_number = self.best_block_number();
@ -175,6 +212,11 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
// build appropriate filter // build appropriate filter
let mut filter: EthcoreFilter = filter.clone().into(); let mut filter: EthcoreFilter = filter.clone().into();
// retrieve reorg logs
let (mut reorg, reorg_len) = last_block_hash.map_or_else(|| (Vec::new(), 0), |h| self.removed_logs(h, &filter));
*block_number -= reorg_len as u64;
filter.from_block = BlockId::Number(*block_number); filter.from_block = BlockId::Number(*block_number);
filter.to_block = BlockId::Latest; filter.to_block = BlockId::Latest;
@ -200,9 +242,14 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
// we want to get logs // we want to get logs
*block_number = current_number + 1; *block_number = current_number + 1;
// save the current block hash, which we used to get back to the
// canon chain in case of reorg.
*last_block_hash = self.block_hash(BlockId::Number(current_number));
// retrieve logs in range from_block..min(BlockId::Latest..to_block) // retrieve logs in range from_block..min(BlockId::Latest..to_block)
let limit = filter.limit; let limit = filter.limit;
Either::B(self.logs(filter) Either::B(self.logs(filter)
.map(move |logs| { reorg.extend(logs); reorg }) // append reorg logs in the front
.map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs .map(move |mut logs| { logs.extend(pending); logs }) // append fetched pending logs
.map(move |logs| limit_logs(logs, limit)) // limit the logs .map(move |logs| limit_logs(logs, limit)) // limit the logs
.map(FilterChanges::Logs)) .map(FilterChanges::Logs))
@ -216,7 +263,7 @@ impl<T: Filterable + Send + Sync + 'static> EthFilter for T {
let mut polls = self.polls().lock(); let mut polls = self.polls().lock();
match polls.poll(&index.value()) { match polls.poll(&index.value()) {
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => filter.clone(), Some(&PollFilter::Logs(ref _block_number, ref _last_block_hash, ref _previous_log, ref filter)) => filter.clone(),
// just empty array // just empty array
Some(_) => return Box::new(future::ok(Vec::new())), Some(_) => return Box::new(future::ok(Vec::new())),
None => return Box::new(future::err(errors::filter_not_found())), None => return Box::new(future::err(errors::filter_not_found())),

View File

@ -18,6 +18,7 @@
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::time::Duration;
use jsonrpc_core::{BoxFuture, Result, Error}; use jsonrpc_core::{BoxFuture, Result, Error};
use jsonrpc_core::futures::{self, Future, IntoFuture}; use jsonrpc_core::futures::{self, Future, IntoFuture};
@ -33,7 +34,7 @@ use v1::types::{pubsub, RichHeader, Log};
use ethcore::encoded; use ethcore::encoded;
use ethcore::filter::Filter as EthFilter; use ethcore::filter::Filter as EthFilter;
use ethcore::client::{BlockChainClient, ChainNotify, BlockId}; use ethcore::client::{BlockChainClient, ChainNotify, ChainRoute, ChainRouteType, BlockId};
use sync::LightSync; use sync::LightSync;
use light::cache::Cache; use light::cache::Cache;
use light::on_demand::OnDemand; use light::on_demand::OnDemand;
@ -140,19 +141,20 @@ impl<C> ChainNotificationHandler<C> {
} }
} }
fn notify_logs<F, T>(&self, enacted: &[H256], logs: F) where fn notify_logs<F, T, Ex>(&self, enacted: &[(H256, Ex)], logs: F) where
F: Fn(EthFilter) -> T, F: Fn(EthFilter, &Ex) -> T,
Ex: Send,
T: IntoFuture<Item = Vec<Log>, Error = Error>, T: IntoFuture<Item = Vec<Log>, Error = Error>,
T::Future: Send + 'static, T::Future: Send + 'static,
{ {
for &(ref subscriber, ref filter) in self.logs_subscribers.read().values() { for &(ref subscriber, ref filter) in self.logs_subscribers.read().values() {
let logs = futures::future::join_all(enacted let logs = futures::future::join_all(enacted
.iter() .iter()
.map(|hash| { .map(|&(hash, ref ex)| {
let mut filter = filter.clone(); let mut filter = filter.clone();
filter.from_block = BlockId::Hash(*hash); filter.from_block = BlockId::Hash(hash);
filter.to_block = filter.from_block.clone(); filter.to_block = filter.from_block.clone();
logs(filter).into_future() logs(filter, ex).into_future()
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
); );
@ -213,7 +215,7 @@ impl<C: LightClient> LightChainNotify for ChainNotificationHandler<C> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.notify_heads(&headers); self.notify_heads(&headers);
self.notify_logs(&enacted, |filter| self.client.logs(filter)) self.notify_logs(&enacted.iter().map(|h| (*h, ())).collect::<Vec<_>>(), |filter, _| self.client.logs(filter))
} }
} }
@ -222,17 +224,21 @@ impl<C: BlockChainClient> ChainNotify for ChainNotificationHandler<C> {
&self, &self,
_imported: Vec<H256>, _imported: Vec<H256>,
_invalid: Vec<H256>, _invalid: Vec<H256>,
enacted: Vec<H256>, route: ChainRoute,
retracted: Vec<H256>,
_sealed: Vec<H256>, _sealed: Vec<H256>,
// Block bytes. // Block bytes.
_proposed: Vec<Bytes>, _proposed: Vec<Bytes>,
_duration: u64, _duration: Duration,
) { ) {
const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed"; const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed";
let headers = enacted let headers = route.route()
.iter() .iter()
.filter_map(|hash| self.client.block_header(BlockId::Hash(*hash))) .filter_map(|&(hash, ref typ)| {
match typ {
&ChainRouteType::Retracted => None,
&ChainRouteType::Enacted => self.client.block_header(BlockId::Hash(hash))
}
})
.map(|header| { .map(|header| {
let hash = header.hash(); let hash = header.hash();
(header, self.client.block_extra_info(BlockId::Hash(hash)).expect(EXTRA_INFO_PROOF)) (header, self.client.block_extra_info(BlockId::Hash(hash)).expect(EXTRA_INFO_PROOF))
@ -242,17 +248,18 @@ impl<C: BlockChainClient> ChainNotify for ChainNotificationHandler<C> {
// Headers // Headers
self.notify_heads(&headers); self.notify_heads(&headers);
// Enacted logs // We notify logs enacting and retracting as the order in route.
self.notify_logs(&enacted, |filter| { self.notify_logs(route.route(), |filter, ex| {
Ok(self.client.logs(filter).into_iter().map(Into::into).collect()) match ex {
}); &ChainRouteType::Enacted =>
Ok(self.client.logs(filter).into_iter().map(Into::into).collect()),
// Retracted logs &ChainRouteType::Retracted =>
self.notify_logs(&retracted, |filter| { Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| {
Ok(self.client.logs(filter).into_iter().map(Into::into).map(|mut log: Log| { log.log_type = "removed".into();
log.log_type = "removed".into(); log.removed = true;
log log
}).collect()) }).collect()),
}
}); });
} }
} }

View File

@ -529,8 +529,8 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
impl<T: LightChainClient + 'static> Filterable for EthClient<T> { impl<T: LightChainClient + 'static> Filterable for EthClient<T> {
fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number } fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number }
fn block_hash(&self, id: BlockId) -> Option<RpcH256> { fn block_hash(&self, id: BlockId) -> Option<::ethereum_types::H256> {
self.client.block_hash(id).map(Into::into) self.client.block_hash(id)
} }
fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> { fn pending_transactions_hashes(&self) -> Vec<::ethereum_types::H256> {
@ -548,6 +548,10 @@ impl<T: LightChainClient + 'static> Filterable for EthClient<T> {
fn polls(&self) -> &Mutex<PollManager<PollFilter>> { fn polls(&self) -> &Mutex<PollManager<PollFilter>> {
&self.polls &self.polls
} }
fn removed_logs(&self, _block_hash: ::ethereum_types::H256, _filter: &EthcoreFilter) -> (Vec<Log>, u64) {
(Default::default(), 0)
}
} }
fn extract_uncle_at_index<T: LightChainClient>(block: encoded::Block, index: Index, client: Arc<T>) -> Option<RichBlock> { fn extract_uncle_at_index<T: LightChainClient>(block: encoded::Block, index: Index, client: Arc<T>) -> Option<RichBlock> {

View File

@ -92,11 +92,11 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
let dispatcher = self.dispatcher.clone(); let dispatcher = self.dispatcher.clone();
let signer = self.signer.clone(); let signer = self.signer.clone();
Box::new(signer.peek(&id).map(|confirmation| { Box::new(signer.take(&id).map(|sender| {
let mut payload = confirmation.payload.clone(); let mut payload = sender.request.payload.clone();
// Modify payload // Modify payload
if let ConfirmationPayload::SendTransaction(ref mut request) = payload { if let ConfirmationPayload::SendTransaction(ref mut request) = payload {
if let Some(sender) = modification.sender.clone() { if let Some(sender) = modification.sender {
request.from = sender.into(); request.from = sender.into();
// Altering sender should always reset the nonce. // Altering sender should always reset the nonce.
request.nonce = None; request.nonce = None;
@ -115,7 +115,9 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
Either::A(fut.into_future().then(move |result| { Either::A(fut.into_future().then(move |result| {
// Execute // Execute
if let Ok(ref response) = result { if let Ok(ref response) = result {
signer.request_confirmed(id, Ok((*response).clone())); signer.request_confirmed(sender, Ok((*response).clone()));
} else {
signer.request_untouched(sender);
} }
result result
@ -194,8 +196,9 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result<ConfirmationResponse> { fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result<ConfirmationResponse> {
let id = id.into(); let id = id.into();
self.signer.peek(&id).map(|confirmation| { self.signer.take(&id).map(|sender| {
let result = match confirmation.payload { let payload = sender.request.payload.clone();
let result = match payload {
ConfirmationPayload::SendTransaction(request) => { ConfirmationPayload::SendTransaction(request) => {
Self::verify_transaction(bytes, request, |pending_transaction| { Self::verify_transaction(bytes, request, |pending_transaction| {
self.dispatcher.dispatch_transaction(pending_transaction) self.dispatcher.dispatch_transaction(pending_transaction)
@ -224,14 +227,16 @@ impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
}, },
}; };
if let Ok(ref response) = result { if let Ok(ref response) = result {
self.signer.request_confirmed(id, Ok(response.clone())); self.signer.request_confirmed(sender, Ok(response.clone()));
} else {
self.signer.request_untouched(sender);
} }
result result
}).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id))) }).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id)))
} }
fn reject_request(&self, id: U256) -> Result<bool> { fn reject_request(&self, id: U256) -> Result<bool> {
let res = self.signer.request_rejected(id.into()); let res = self.signer.take(&id.into()).map(|sender| self.signer.request_rejected(sender));
Ok(res.is_some()) Ok(res.is_some())
} }

View File

@ -155,7 +155,14 @@ impl MinerService for TestMinerService {
} }
/// Imports transactions to transaction queue. /// Imports transactions to transaction queue.
fn import_own_transaction<C: Nonce + Sync>(&self, chain: &C, pending: PendingTransaction) fn import_own_transaction<C: Nonce + Sync>(&self, _chain: &C, _pending: PendingTransaction)
-> Result<(), transaction::Error> {
// this function is no longer called directly from RPC
unimplemented!();
}
/// Imports transactions to queue - treats as local based on trusted flag, config, and tx source
fn import_claimed_local_transaction<C: Nonce + Sync>(&self, chain: &C, pending: PendingTransaction, _trusted: bool)
-> Result<(), transaction::Error> { -> Result<(), transaction::Error> {
// keep the pending nonces up to date // keep the pending nonces up to date

View File

@ -226,8 +226,8 @@ fn rpc_eth_logs() {
let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#; let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#;
let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#; let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#;
let response3 = r#"{"jsonrpc":"2.0","result":[],"id":1}"#; let response3 = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned())); assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned()));
@ -276,8 +276,8 @@ fn rpc_logs_filter() {
let request_changes1 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x0"], "id": 1}"#; let request_changes1 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x0"], "id": 1}"#;
let request_changes2 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], "id": 1}"#; let request_changes2 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#; let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x1","removed":false,"topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x1","type":"mined"}],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request_changes1), Some(response1.to_owned())); assert_eq!(tester.io.handle_request_sync(request_changes1), Some(response1.to_owned()));
assert_eq!(tester.io.handle_request_sync(request_changes2), Some(response2.to_owned())); assert_eq!(tester.io.handle_request_sync(request_changes2), Some(response2.to_owned()));
@ -1045,7 +1045,7 @@ fn rpc_eth_transaction_receipt() {
"params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],
"id": 1 "id": 1
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","removed":false,"topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","status":null,"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }

View File

@ -20,11 +20,15 @@ use jsonrpc_core::MetaIoHandler;
use jsonrpc_core::futures::{self, Stream, Future}; use jsonrpc_core::futures::{self, Stream, Future};
use jsonrpc_pubsub::Session; use jsonrpc_pubsub::Session;
use std::time::Duration;
use v1::{EthPubSub, EthPubSubClient, Metadata}; use v1::{EthPubSub, EthPubSubClient, Metadata};
use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify}; use ethcore::client::{TestBlockChainClient, EachBlockWith, ChainNotify, ChainRoute, ChainRouteType};
use parity_reactor::EventLoop; use parity_reactor::EventLoop;
const DURATION_ZERO: Duration = Duration::from_millis(0);
#[test] #[test]
fn should_subscribe_to_new_heads() { fn should_subscribe_to_new_heads() {
// given // given
@ -53,13 +57,13 @@ fn should_subscribe_to_new_heads() {
assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned()));
// Check notifications // Check notifications
handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO);
let (res, receiver) = receiver.into_future().wait().unwrap(); let (res, receiver) = receiver.into_future().wait().unwrap();
let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#; let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"author":"0x0000000000000000000000000000000000000000","difficulty":"0x1","extraData":"0x","gasLimit":"0xf4240","gasUsed":"0x0","hash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","number":"0x1","parentHash":"0x0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":[],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x1c9","stateRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","timestamp":"0x0","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"},"subscription":"0x416d77337e24399d"}}"#;
assert_eq!(res, Some(response.into())); assert_eq!(res, Some(response.into()));
// Notify about two blocks // Notify about two blocks
handler.new_blocks(vec![], vec![], vec![h2, h3], vec![], vec![], vec![], 0); handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h2, ChainRouteType::Enacted), (h3, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO);
// Receive both // Receive both
let (res, receiver) = receiver.into_future().wait().unwrap(); let (res, receiver) = receiver.into_future().wait().unwrap();
@ -125,17 +129,17 @@ fn should_subscribe_to_logs() {
assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request, metadata.clone()), Some(response.to_owned()));
// Check notifications (enacted) // Check notifications (enacted)
handler.new_blocks(vec![], vec![], vec![h1], vec![], vec![], vec![], 0); handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Enacted)]), vec![], vec![], DURATION_ZERO);
let (res, receiver) = receiver.into_future().wait().unwrap(); let (res, receiver) = receiver.into_future().wait().unwrap();
let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","removed":false,"topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned()
+ &format!("0x{:x}", tx_hash) + &format!("0x{:x}", tx_hash)
+ r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},"subscription":"0x416d77337e24399d"}}"#; + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"mined"},"subscription":"0x416d77337e24399d"}}"#;
assert_eq!(res, Some(response.into())); assert_eq!(res, Some(response.into()));
// Check notifications (retracted) // Check notifications (retracted)
handler.new_blocks(vec![], vec![], vec![], vec![h1], vec![], vec![], 0); handler.new_blocks(vec![], vec![], ChainRoute::new(vec![(h1, ChainRouteType::Retracted)]), vec![], vec![], DURATION_ZERO);
let (res, receiver) = receiver.into_future().wait().unwrap(); let (res, receiver) = receiver.into_future().wait().unwrap();
let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned() let response = r#"{"jsonrpc":"2.0","method":"eth_subscription","params":{"result":{"address":"0x0000000000000000000000000000000000000005","blockHash":"0x3457d2fa2e3dd33c78ac681cf542e429becf718859053448748383af67e23218","blockNumber":"0x1","data":"0x","logIndex":"0x0","removed":true,"topics":["0x0000000000000000000000000000000000000000000000000000000000000001","0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000000","0x0000000000000000000000000000000000000000000000000000000000000000"],"transactionHash":""#.to_owned()
+ &format!("0x{:x}", tx_hash) + &format!("0x{:x}", tx_hash)
+ r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"removed"},"subscription":"0x416d77337e24399d"}}"#; + r#"","transactionIndex":"0x0","transactionLogIndex":"0x0","type":"removed"},"subscription":"0x416d77337e24399d"}}"#;
assert_eq!(res, Some(response.into())); assert_eq!(res, Some(response.into()));

View File

@ -110,7 +110,8 @@ fn should_add_sign_to_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::Signature(0.into()))); let sender = signer.take(&1.into()).unwrap();
signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(0.into())));
break break
} }
::std::thread::sleep(Duration::from_millis(100)) ::std::thread::sleep(Duration::from_millis(100))
@ -188,7 +189,8 @@ fn should_check_status_of_request_when_its_resolved() {
"id": 1 "id": 1
}"#; }"#;
tester.io.handle_request_sync(&request).expect("Sent"); tester.io.handle_request_sync(&request).expect("Sent");
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(1.into()))); let sender = tester.signer.take(&1.into()).unwrap();
tester.signer.request_confirmed(sender, Ok(ConfirmationResponse::Signature(1.into())));
// This is not ideal, but we need to give futures some time to be executed, and they need to run in a separate thread // This is not ideal, but we need to give futures some time to be executed, and they need to run in a separate thread
thread::sleep(Duration::from_millis(20)); thread::sleep(Duration::from_millis(20));
@ -259,7 +261,8 @@ fn should_add_transaction_to_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::SendTransaction(0.into()))); let sender = signer.take(&1.into()).unwrap();
signer.request_confirmed(sender, Ok(ConfirmationResponse::SendTransaction(0.into())));
break break
} }
::std::thread::sleep(Duration::from_millis(100)) ::std::thread::sleep(Duration::from_millis(100))
@ -335,7 +338,8 @@ 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( let sender = signer.take(&1.into()).unwrap();
signer.request_confirmed(sender, Ok(ConfirmationResponse::SignTransaction(
RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value()) RichRawTransaction::from_signed(t.into(), 0x0, u64::max_value())
))); )));
break break
@ -442,7 +446,8 @@ fn should_add_decryption_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::Decrypt(vec![0x1, 0x2].into()))); let sender = signer.take(&1.into()).unwrap();
signer.request_confirmed(sender, Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
break break
} }
::std::thread::sleep(Duration::from_millis(10)) ::std::thread::sleep(Duration::from_millis(10))

View File

@ -47,6 +47,9 @@ pub struct Log {
/// Log Type /// Log Type
#[serde(rename="type")] #[serde(rename="type")]
pub log_type: String, pub log_type: String,
/// Whether Log Type is Removed (Geth Compatibility Field)
#[serde(default)]
pub removed: bool,
} }
impl From<LocalizedLogEntry> for Log { impl From<LocalizedLogEntry> for Log {
@ -62,6 +65,7 @@ impl From<LocalizedLogEntry> for Log {
log_index: Some(e.log_index.into()), log_index: Some(e.log_index.into()),
transaction_log_index: Some(e.transaction_log_index.into()), transaction_log_index: Some(e.transaction_log_index.into()),
log_type: "mined".to_owned(), log_type: "mined".to_owned(),
removed: false,
} }
} }
} }
@ -79,6 +83,7 @@ impl From<LogEntry> for Log {
log_index: None, log_index: None,
transaction_log_index: None, transaction_log_index: None,
log_type: "pending".to_owned(), log_type: "pending".to_owned(),
removed: false,
} }
} }
} }
@ -91,7 +96,7 @@ mod tests {
#[test] #[test]
fn log_serialization() { fn log_serialization() {
let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":"0x1","type":"mined"}"#; let s = r#"{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","transactionLogIndex":"0x1","type":"mined","removed":false}"#;
let log = Log { let log = Log {
address: H160::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), address: H160::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(),
@ -107,6 +112,7 @@ mod tests {
transaction_log_index: Some(1.into()), transaction_log_index: Some(1.into()),
log_index: Some(U256::from(1)), log_index: Some(U256::from(1)),
log_type: "mined".to_owned(), log_type: "mined".to_owned(),
removed: false,
}; };
let serialized = serde_json::to_string(&log).unwrap(); let serialized = serde_json::to_string(&log).unwrap();

View File

@ -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":"0x1"}"#; 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","removed":false}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f","status":"0x1"}"#;
let receipt = Receipt { let receipt = Receipt {
transaction_hash: Some(0.into()), transaction_hash: Some(0.into()),
@ -155,6 +155,7 @@ mod tests {
transaction_log_index: None, transaction_log_index: None,
log_index: Some(1.into()), log_index: Some(1.into()),
log_type: "mined".into(), log_type: "mined".into(),
removed: false,
}], }],
logs_bloom: 15.into(), logs_bloom: 15.into(),
state_root: Some(10.into()), state_root: Some(10.into()),
@ -165,4 +166,3 @@ mod tests {
assert_eq!(serialized, s); assert_eq!(serialized, s);
} }
} }

View File

@ -16,8 +16,9 @@
use std::sync::Arc; use std::sync::Arc;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::time::Duration;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo}; use ethcore::client::{BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo};
use ethereum_types::{H256, Address}; use ethereum_types::{H256, Address};
use bytes::Bytes; use bytes::Bytes;
use trusted_client::TrustedClient; use trusted_client::TrustedClient;
@ -75,8 +76,8 @@ impl AclStorage for OnChainAclStorage {
} }
impl ChainNotify for OnChainAclStorage { impl ChainNotify for OnChainAclStorage {
fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, enacted: Vec<H256>, retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) { fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
if !enacted.is_empty() || !retracted.is_empty() { if !route.enacted().is_empty() || !route.retracted().is_empty() {
self.contract.lock().update() self.contract.lock().update()
} }
} }

View File

@ -17,8 +17,9 @@
use std::sync::Arc; use std::sync::Arc;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::time::Duration;
use parking_lot::Mutex; use parking_lot::Mutex;
use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo}; use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, ChainRoute, CallContract, RegistryInfo};
use ethcore::filter::Filter; use ethcore::filter::Filter;
use ethkey::public_to_address; use ethkey::public_to_address;
use hash::keccak; use hash::keccak;
@ -162,7 +163,9 @@ impl KeyServerSet for OnChainKeyServerSet {
} }
impl ChainNotify for OnChainKeyServerSet { impl ChainNotify for OnChainKeyServerSet {
fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, enacted: Vec<H256>, retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) { fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
let (enacted, retracted) = route.into_enacted_retracted();
if !enacted.is_empty() || !retracted.is_empty() { if !enacted.is_empty() || !retracted.is_empty() {
self.contract.lock().update(enacted, retracted) self.contract.lock().update(enacted, retracted)
} }

View File

@ -17,9 +17,10 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use std::thread; use std::thread;
use parking_lot::Mutex; use parking_lot::Mutex;
use ethcore::client::ChainNotify; use ethcore::client::{ChainNotify, ChainRoute};
use ethkey::{Public, public_to_address}; use ethkey::{Public, public_to_address};
use bytes::Bytes; use bytes::Bytes;
use ethereum_types::{H256, U256, Address}; use ethereum_types::{H256, U256, Address};
@ -428,8 +429,8 @@ impl Drop for ServiceContractListener {
} }
impl ChainNotify for ServiceContractListener { impl ChainNotify for ServiceContractListener {
fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) { fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
let enacted_len = enacted.len(); let enacted_len = route.enacted().len();
if enacted_len == 0 { if enacted_len == 0 {
return; return;
} }

View File

@ -28,7 +28,7 @@ use target_info::Target;
use bytes::Bytes; use bytes::Bytes;
use ethcore::BlockNumber; use ethcore::BlockNumber;
use ethcore::filter::Filter; use ethcore::filter::Filter;
use ethcore::client::{BlockId, BlockChainClient, ChainNotify}; use ethcore::client::{BlockId, BlockChainClient, ChainNotify, ChainRoute};
use ethereum_types::H256; use ethereum_types::H256;
use sync::{SyncProvider}; use sync::{SyncProvider};
use hash_fetch::{self as fetch, HashFetch}; use hash_fetch::{self as fetch, HashFetch};
@ -660,7 +660,7 @@ impl<O: OperationsClient, F: HashFetch, T: TimeProvider, R: GenRange> Updater<O,
} }
impl ChainNotify for Updater { impl ChainNotify for Updater {
fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, _enacted: Vec<H256>, _retracted: Vec<H256>, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: u64) { fn new_blocks(&self, _imported: Vec<H256>, _invalid: Vec<H256>, _route: ChainRoute, _sealed: Vec<H256>, _proposed: Vec<Bytes>, _duration: Duration) {
match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) { match (self.client.upgrade(), self.sync.as_ref().and_then(Weak::upgrade)) {
(Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(), (Some(ref c), Some(ref s)) if !s.status().is_syncing(c.queue_info()) => self.poll(),
_ => {}, _ => {},