[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:
parent
f26a7fe6fa
commit
cc44ae9cb5
@ -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
70
Cargo.lock
generated
@ -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"
|
||||||
|
@ -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)
|
||||||
|
@ -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() {
|
||||||
|
@ -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 } } } },
|
||||||
|
@ -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",
|
||||||
|
@ -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.
|
||||||
|
@ -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>,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]]),
|
||||||
|
@ -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,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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" }
|
||||||
|
@ -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;
|
||||||
|
@ -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| ())
|
||||||
|
@ -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)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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,
|
||||||
|
@ -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"]
|
||||||
|
@ -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()?,
|
||||||
|
@ -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)",
|
||||||
|
@ -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) => {
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
|
@ -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())),
|
||||||
|
@ -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()),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -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()));
|
||||||
|
@ -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))
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
_ => {},
|
_ => {},
|
||||||
|
Loading…
Reference in New Issue
Block a user