Merge branch 'master' into tx-cache
This commit is contained in:
commit
f4690712d0
|
@ -61,6 +61,14 @@ dependencies = [
|
|||
"odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aster"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base58"
|
||||
version = "0.1.0"
|
||||
|
@ -140,6 +148,15 @@ dependencies = [
|
|||
"yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.2.10"
|
||||
|
@ -191,6 +208,11 @@ dependencies = [
|
|||
"tokio-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "elastic-array"
|
||||
version = "0.5.0"
|
||||
|
@ -258,6 +280,40 @@ dependencies = [
|
|||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.0-a.0"
|
||||
source = "git+https://github.com/ethcore/hyper#7d4f7fa0baddcb2b0c523f7c05855d67de94fe88"
|
||||
dependencies = [
|
||||
"cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rotor 0.6.3 (git+https://github.com/ethcore/rotor)",
|
||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "import"
|
||||
version = "0.1.0"
|
||||
|
@ -268,6 +324,34 @@ dependencies = [
|
|||
"serialization 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-core"
|
||||
version = "4.0.0"
|
||||
source = "git+https://github.com/ethcore/jsonrpc.git#1500da1b9613a0a17fc0109d825f3ccc60199a53"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonrpc-http-server"
|
||||
version = "6.1.1"
|
||||
source = "git+https://github.com/ethcore/jsonrpc.git#1500da1b9613a0a17fc0109d825f3ccc60199a53"
|
||||
dependencies = [
|
||||
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
|
||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
|
@ -290,6 +374,11 @@ dependencies = [
|
|||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.2"
|
||||
|
@ -338,6 +427,11 @@ dependencies = [
|
|||
"linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.11"
|
||||
|
@ -358,6 +452,14 @@ dependencies = [
|
|||
"serialization 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miner"
|
||||
version = "0.1.0"
|
||||
|
@ -370,6 +472,22 @@ dependencies = [
|
|||
"test-data 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.1"
|
||||
source = "git+https://github.com/ethcore/mio.git#ef182bae193a9c7457cd2cf661fcaffb226e3eef"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.1"
|
||||
|
@ -458,6 +576,11 @@ dependencies = [
|
|||
"tokio-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.2.0"
|
||||
|
@ -506,6 +629,17 @@ dependencies = [
|
|||
"tokio-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.3.6"
|
||||
|
@ -545,6 +679,7 @@ dependencies = [
|
|||
"miner 0.1.0",
|
||||
"network 0.1.0",
|
||||
"p2p 0.1.0",
|
||||
"rpc 0.1.0",
|
||||
"script 0.1.0",
|
||||
"sync 0.1.0",
|
||||
"verification 0.1.0",
|
||||
|
@ -559,6 +694,34 @@ dependencies = [
|
|||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quasi"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quasi_codegen"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quasi_macros"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quasi_codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.1.0"
|
||||
|
@ -618,6 +781,41 @@ dependencies = [
|
|||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rotor"
|
||||
version = "0.6.3"
|
||||
source = "git+https://github.com/ethcore/rotor#c1a2dd0046c5ea2517a5b637fca8ee2e77021e82"
|
||||
dependencies = [
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.1 (git+https://github.com/ethcore/mio.git)",
|
||||
"quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chain 0.1.0",
|
||||
"db 0.1.0",
|
||||
"jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
|
||||
"jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"network 0.1.0",
|
||||
"p2p 0.1.0",
|
||||
"primitives 0.1.0",
|
||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_macros 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serialization 0.1.0",
|
||||
"sync 0.1.0",
|
||||
"test-data 0.1.0",
|
||||
"tokio-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-crypto"
|
||||
version = "0.2.36"
|
||||
|
@ -680,6 +878,53 @@ name = "semver"
|
|||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi_codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi_macros 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_codegen_internals 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_codegen_internals"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_macros"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_codegen 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serialization"
|
||||
version = "0.1.0"
|
||||
|
@ -712,6 +957,11 @@ name = "smallvec"
|
|||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "spmc"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.5.2"
|
||||
|
@ -747,6 +997,60 @@ dependencies = [
|
|||
"verification 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntex"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntex_errors"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_pos 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntex_pos"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntex_syntax"
|
||||
version = "0.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_pos 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.2.1"
|
||||
|
@ -806,6 +1110,27 @@ dependencies = [
|
|||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "0.1.2"
|
||||
|
@ -816,6 +1141,20 @@ name = "unicode-width"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
|
@ -831,6 +1170,15 @@ name = "vec_map"
|
|||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vecio"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (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 = "void"
|
||||
version = "1.0.2"
|
||||
|
@ -871,6 +1219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4"
|
||||
"checksum arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d89f1b0e242270b5b797778af0c8d182a1a2ccac5d8d6fadf414223cc0fab096"
|
||||
"checksum aster 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258989846dd255a1e0eeef92d425d345477c9999433cecc9f0879f4549d5e5c9"
|
||||
"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
|
||||
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
|
||||
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
||||
|
@ -878,10 +1227,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||
"checksum clap 2.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef87e92396a3d29bf7e611c8a595be35ae90d9cb844a3571425900eaca4f51c8"
|
||||
"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591"
|
||||
"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
|
||||
"checksum csv 0.14.7 (registry+https://github.com/rust-lang/crates.io-index)" = "266c1815d7ca63a5bd86284043faf91e8c95e943e55ce05dc0ae08e952de18bc"
|
||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||
"checksum domain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "725459994103308a8476a95d8115280b1359dccc06ca14291df75f37459a9e30"
|
||||
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
||||
"checksum elastic-array 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bc9250a632e7c001b741eb0ec6cee93c9a5b6d5f1879696a4b94d62b012210a"
|
||||
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
||||
"checksum eth-secp256k1 0.5.6 (git+https://github.com/ethcore/rust-secp256k1)" = "<none>"
|
||||
|
@ -889,7 +1240,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bb982bb25cd8fa5da6a8eb3a460354c984ff1113da82bcb4f0b0862b5795db82"
|
||||
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
||||
"checksum heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8c80e194758495a9109566134dc06e42ea0423987d6ceca016edaa90381b3549"
|
||||
"checksum httparse 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e7a63e511f9edffbab707141fbb8707d1a3098615fb2adbd5769cdfcc9b17d"
|
||||
"checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "<none>"
|
||||
"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11"
|
||||
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
|
||||
"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
||||
"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b"
|
||||
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
|
||||
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
|
||||
|
@ -897,7 +1255,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
|
||||
"checksum lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656fa4dfcb02bcf1063c592ba3ff6a5303ee1f2afe98c8a889e8b1a77c6dfdb7"
|
||||
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
|
||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||
"checksum mime 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5c93a4bd787ddc6e7833c519b73a50883deb5863d76d9b71eb8216fb7f94e66"
|
||||
"checksum mio 0.6.1 (git+https://github.com/ethcore/mio.git)" = "<none>"
|
||||
"checksum mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "410a1a0ff76f5a226f1e4e3ff1756128e65cd30166e39c3892283e2ac09d5b67"
|
||||
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a"
|
||||
"checksum murmur3 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ece7fe85164ffce69891c581b6b035a3c2f66dd3459f299d43d5efff90663e22"
|
||||
|
@ -905,12 +1266,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
|
||||
"checksum nodrop 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbadd3f4c98dea0bd3d9b4be4c0cdaf1ab57035cb2e41fce3983db5add7cc5"
|
||||
"checksum ns-dns-tokio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43330aab5077c311b390b62147feb44316cb5b754b97d28c92210e6c6b7baff7"
|
||||
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
|
||||
"checksum num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55aabf4e2d6271a2e4e4c0f2ea1f5b07cc589cc1a9e9213013b54a76678ca4f3"
|
||||
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
|
||||
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
||||
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
|
||||
"checksum parking_lot 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "968f685642555d2f7e202c48b8b11de80569e9bfea817f7f12d7c61aac62d4e6"
|
||||
"checksum parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e1435e7a2a00dfebededd6c6bdbd54008001e94b4a2aadd6aef0dc4c56317621"
|
||||
"checksum parking_lot_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb1b97670a2ffadce7c397fb80a3d687c4f3060140b885621ef1653d0e5d5068"
|
||||
"checksum quasi 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94a532453b931a4483a5b2e40f0fe04aee35b6bc2c0eeec876f1bd2358a134d3"
|
||||
"checksum quasi_codegen 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb4a9a5410fdbdacbeda8063ddb8add9838dfd4cf50ac486db98abb762d8bd6"
|
||||
"checksum quasi_macros 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "adc2b36285ea5e54e4e267f83896267ff8c5aba4f66b2e7d186ed6d968f3715f"
|
||||
"checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c"
|
||||
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
|
||||
"checksum rayon 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0783f5880c56f5a308e219ac9309dbe781e064741dd5def4c617c440890305"
|
||||
|
@ -918,6 +1284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||
"checksum rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
||||
"checksum rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)" = "<none>"
|
||||
"checksum rotor 0.6.3 (git+https://github.com/ethcore/rotor)" = "<none>"
|
||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
|
||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||
|
@ -925,21 +1292,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
|
||||
"checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
|
||||
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
|
||||
"checksum serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)" = "58a19c0871c298847e6b68318484685cd51fa5478c0c905095647540031356e5"
|
||||
"checksum serde_codegen 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "da68810d845f8e33a80243c28794650397056cbe7aea4c9c7516f55d1061c94e"
|
||||
"checksum serde_codegen_internals 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1b0115c5c602e81c61b787fb0f0fa76a614f8dbe9100b2b59b7d590155672c80"
|
||||
"checksum serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7d3c184d35801fb8b32b46a7d58d57dbcc150b0eb2b46a1eb79645e8ecfd5b"
|
||||
"checksum serde_macros 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c3cf1c01933271e1e72bb788e0499d1bca8af2c09efcc3ddc0b04ff22d080b83"
|
||||
"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d"
|
||||
"checksum siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "833011ca526bd88f16778d32c699d325a9ad302fa06381cd66f7be63351d3f6d"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum smallvec 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fcc8d19212aacecf95e4a7a2179b26f7aeb9732a915cf01f05b0d3e044865410"
|
||||
"checksum spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93bdab61c1a413e591c4d17388ffa859eaff2df27f1e13a5ec8b716700605adf"
|
||||
"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c"
|
||||
"checksum syntex 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "84f37b94d7ee762bcac58741f73a95465cf87188c3b93f10df9245aff821b2b4"
|
||||
"checksum syntex_errors 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0d95d2141ae79f312a01c6934d9984f9d7f5cfaf0c74aae5fbbc234a6dcb77a"
|
||||
"checksum syntex_pos 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2cbf0598c5970f2dca122a4e6f7e93bf42f2d0b2dd88c3ea112413152864df"
|
||||
"checksum syntex_syntax 0.44.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a89ee386d492cdd3855becec489c25797bb91bcbb3c2478c41969b24cb318a2"
|
||||
"checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a"
|
||||
"checksum term_size 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f7f5f3f71b0040cecc71af239414c23fd3c73570f5ff54cf50e03cef637f2a0"
|
||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
|
||||
"checksum tokio-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06f40e15561569e24dab3dcf270c0bb950195b84dbed591dfb6591e28c9b9cff"
|
||||
"checksum unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13a5906ca2b98c799f4b1ab4557b76367ebd6ae5ef14930ec841c74aed5f3764"
|
||||
"checksum unicode-bidi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c1f7ceb96afdfeedee42bade65a0d585a6a0106f681b6749c8ff4daa8df30b3f"
|
||||
"checksum unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "26643a2f83bac55f1976fb716c10234485f9202dcd65cfbdf9da49867b271172"
|
||||
"checksum unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b905d0fc2a1f0befd86b0e72e31d1787944efef9d38b9358a9e92a69757f7e3b"
|
||||
"checksum unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6722facc10989f63ee0e20a83cd4e1714a9ae11529403ac7e0afd069abc39e"
|
||||
"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb"
|
||||
"checksum url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "48ccf7bd87a81b769cf84ad556e034541fb90e1cd6d4bc375c822ed9500cd9d7"
|
||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||
"checksum variance 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3abfc2be1fb59663871379ea884fd81de80c496f2274e021c01d6fe56cd77b05"
|
||||
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
|
||||
"checksum vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0795a11576d29ae80525a3fda315bf7b534f8feb9d34101e5fe63fb95bb2fd24"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
|
|
@ -23,6 +23,7 @@ sync = { path = "sync" }
|
|||
import = { path = "import" }
|
||||
bencher = { path = "bencher" }
|
||||
logs = { path = "logs" }
|
||||
rpc = { path = "rpc" }
|
||||
|
||||
[[bin]]
|
||||
path = "pbtc/main.rs"
|
||||
|
|
|
@ -381,47 +381,6 @@ impl Storage {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_n_with_strategy(&self, mut n: usize, strategy: OrderingStrategy) -> Vec<H256> {
|
||||
if n == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
if n == 1 {
|
||||
return self.read_with_strategy(strategy)
|
||||
.map_or(Vec::new(), |h| vec![h]);
|
||||
}
|
||||
|
||||
let mut references = self.references.clone();
|
||||
let mut result: Vec<H256> = Vec::new();
|
||||
let mut removed: HashSet<H256> = HashSet::new();
|
||||
loop {
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
n -= 1;
|
||||
|
||||
let top_hash = match strategy {
|
||||
OrderingStrategy::ByTimestamp => references.ordered.by_storage_index.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
OrderingStrategy::ByTransactionScore => references.ordered.by_transaction_score.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
OrderingStrategy::ByPackageScore => references.ordered.by_package_score.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
};
|
||||
match top_hash {
|
||||
None => break,
|
||||
Some(top_hash) => {
|
||||
self.by_hash.get(&top_hash).map(|entry| {
|
||||
// simulate removal
|
||||
removed.insert(top_hash.clone());
|
||||
references.remove(Some(&removed), &self.by_hash, entry);
|
||||
|
||||
// return this entry
|
||||
result.push(top_hash);
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn remove_by_hash(&mut self, h: &H256) -> Option<Entry> {
|
||||
self.by_hash.remove(h)
|
||||
.map(|entry| {
|
||||
|
@ -634,6 +593,11 @@ impl MemoryPool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Iterator over memory pool transactions according to specified strategy
|
||||
pub fn iter(&self, strategy: OrderingStrategy) -> MemoryPoolIterator {
|
||||
MemoryPoolIterator::new(self, strategy)
|
||||
}
|
||||
|
||||
/// Removes single transaction by its hash.
|
||||
/// All descedants remain in the pool.
|
||||
pub fn remove_by_hash(&mut self, h: &H256) -> Option<Transaction> {
|
||||
|
@ -660,7 +624,7 @@ impl MemoryPool {
|
|||
/// Ancestors are always returned before descendant transactions.
|
||||
/// Use this function with care, only if really needed (heavy memory usage)
|
||||
pub fn read_n_with_strategy(&mut self, n: usize, strategy: OrderingStrategy) -> Vec<H256> {
|
||||
self.storage.read_n_with_strategy(n, strategy)
|
||||
self.iter(strategy).take(n).collect()
|
||||
}
|
||||
|
||||
/// Removes the 'top' transaction from the `MemoryPool` using selected strategy.
|
||||
|
@ -789,6 +753,44 @@ impl HeapSizeOf for MemoryPool {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct MemoryPoolIterator<'a> {
|
||||
memory_pool: &'a MemoryPool,
|
||||
references: ReferenceStorage,
|
||||
removed: HashSet<H256>,
|
||||
strategy: OrderingStrategy,
|
||||
}
|
||||
|
||||
impl<'a> MemoryPoolIterator<'a> {
|
||||
fn new(memory_pool: &'a MemoryPool, strategy: OrderingStrategy) -> Self {
|
||||
MemoryPoolIterator {
|
||||
memory_pool: memory_pool,
|
||||
references: memory_pool.storage.references.clone(),
|
||||
removed: HashSet::new(),
|
||||
strategy: strategy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for MemoryPoolIterator<'a> {
|
||||
type Item = H256;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let top_hash = match self.strategy {
|
||||
OrderingStrategy::ByTimestamp => self.references.ordered.by_storage_index.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
OrderingStrategy::ByTransactionScore => self.references.ordered.by_transaction_score.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
OrderingStrategy::ByPackageScore => self.references.ordered.by_package_score.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||
};
|
||||
|
||||
if let Some(ref top_hash) = top_hash {
|
||||
let entry = self.memory_pool.storage.by_hash.get(top_hash).expect("missing hash is a sign of MemoryPool internal inconsistancy");
|
||||
self.removed.insert(top_hash.clone());
|
||||
self.references.remove(Some(&self.removed), &self.memory_pool.storage.by_hash, entry);
|
||||
}
|
||||
|
||||
top_hash
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use db::PreviousTransactionOutputProvider;
|
||||
|
|
28
pbtc/cli.yml
28
pbtc/cli.yml
|
@ -43,6 +43,34 @@ args:
|
|||
value_name: NET
|
||||
help: Only connect to nodes in network <NET> (ipv4 or ipv6)
|
||||
takes_value: true
|
||||
- no-jsonrpc:
|
||||
long: no-jsonrpc
|
||||
help: Disable the JSON-RPC API server
|
||||
- jsonrpc-port:
|
||||
long: jsonrpc-port
|
||||
help: The port portion of the JSONRPC API server
|
||||
takes_value: true
|
||||
value_name: PORT
|
||||
- jsonrpc-interface:
|
||||
long: jsonrpc-interface
|
||||
help: The hostname portion of the JSONRPC API server
|
||||
takes_value: true
|
||||
value_name: INTERFACE
|
||||
- jsonrpc-cors:
|
||||
long: jsonrpc-cors
|
||||
help: Specify CORS header for JSON-RPC API responses
|
||||
takes_value: true
|
||||
value_name: URL
|
||||
- jsonrpc-apis:
|
||||
long: jsonrpc-apis
|
||||
help: Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited list of API name.
|
||||
takes_value: true
|
||||
value_name: APIS
|
||||
- jsonrpc-hosts:
|
||||
long: jsonrpc-hosts
|
||||
help: List of allowed Host header values
|
||||
takes_value: true
|
||||
value_name: HOSTS
|
||||
subcommands:
|
||||
- import:
|
||||
about: Import blocks from bitcoin core database
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::net::SocketAddr;
|
||||
use sync::create_sync_connection_factory;
|
||||
use sync::{create_local_sync_node, create_sync_connection_factory};
|
||||
use message::Services;
|
||||
use util::{open_db, init_db, node_table_path};
|
||||
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM};
|
||||
use super::super::rpc;
|
||||
|
||||
pub fn start(cfg: config::Config) -> Result<(), String> {
|
||||
let mut el = p2p::event_loop();
|
||||
|
@ -24,7 +25,7 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
|
|||
services: Services::default().with_network(true),
|
||||
user_agent: cfg.user_agent,
|
||||
start_height: 0,
|
||||
relay: false,
|
||||
relay: true,
|
||||
},
|
||||
peers: cfg.connect.map_or_else(|| vec![], |x| vec![x]),
|
||||
seeds: cfg.seednodes,
|
||||
|
@ -33,7 +34,13 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
|
|||
};
|
||||
|
||||
let sync_handle = el.handle();
|
||||
let sync_connection_factory = create_sync_connection_factory(&sync_handle, cfg.magic, db);
|
||||
let local_sync_node = create_local_sync_node(&sync_handle, cfg.magic, db);
|
||||
let sync_connection_factory = create_sync_connection_factory(local_sync_node.clone());
|
||||
|
||||
let rpc_deps = rpc::Dependencies {
|
||||
local_sync_node: local_sync_node,
|
||||
};
|
||||
let _rpc_server = try!(rpc::new_http(cfg.rpc_config, rpc_deps));
|
||||
|
||||
let p2p = try!(p2p::P2P::new(p2p_cfg, sync_connection_factory, el.handle()).map_err(|x| x.to_string()));
|
||||
try!(p2p.run().map_err(|_| "Failed to start p2p module"));
|
||||
|
|
|
@ -3,7 +3,9 @@ use clap;
|
|||
use network::Magic;
|
||||
use p2p::InternetProtocol;
|
||||
use seednodes::{mainnet_seednodes, testnet_seednodes};
|
||||
use rpc_apis::ApiSet;
|
||||
use {USER_AGENT, REGTEST_USER_AGENT};
|
||||
use rpc::HttpConfiguration as RpcHttpConfig;
|
||||
|
||||
pub struct Config {
|
||||
pub magic: Magic,
|
||||
|
@ -18,6 +20,7 @@ pub struct Config {
|
|||
pub data_dir: Option<String>,
|
||||
pub user_agent: String,
|
||||
pub internet_protocol: InternetProtocol,
|
||||
pub rpc_config: RpcHttpConfig,
|
||||
}
|
||||
|
||||
pub const DEFAULT_DB_CACHE: usize = 512;
|
||||
|
@ -86,6 +89,8 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
|
|||
None => InternetProtocol::default(),
|
||||
};
|
||||
|
||||
let rpc_config = try!(parse_rpc_config(magic, matches));
|
||||
|
||||
let config = Config {
|
||||
print_to_console: print_to_console,
|
||||
magic: magic,
|
||||
|
@ -99,7 +104,34 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
|
|||
data_dir: data_dir,
|
||||
user_agent: user_agent.to_string(),
|
||||
internet_protocol: only_net,
|
||||
rpc_config: rpc_config,
|
||||
};
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
fn parse_rpc_config(magic: Magic, matches: &clap::ArgMatches) -> Result<RpcHttpConfig, String> {
|
||||
let mut config = RpcHttpConfig::with_port(magic.rpc_port());
|
||||
config.enabled = !matches.is_present("no-jsonrpc");
|
||||
if !config.enabled {
|
||||
return Ok(config);
|
||||
}
|
||||
|
||||
if let Some(apis) = matches.value_of("jsonrpc-apis") {
|
||||
config.apis = ApiSet::List(vec![try!(apis.parse().map_err(|_| "Invalid APIs".to_owned()))].into_iter().collect());
|
||||
}
|
||||
if let Some(port) = matches.value_of("jsonrpc-port") {
|
||||
config.port = try!(port.parse().map_err(|_| "Invalid JSON RPC port".to_owned()));
|
||||
}
|
||||
if let Some(interface) = matches.value_of("jsonrpc-interface") {
|
||||
config.interface = interface.to_owned();
|
||||
}
|
||||
if let Some(cors) = matches.value_of("jsonrpc-cors") {
|
||||
config.cors = Some(vec![try!(cors.parse().map_err(|_| "Invalid JSON RPC CORS".to_owned()))]);
|
||||
}
|
||||
if let Some(hosts) = matches.value_of("jsonrpc-hosts") {
|
||||
config.hosts = Some(vec![try!(hosts.parse().map_err(|_| "Invalid JSON RPC hosts".to_owned()))]);
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
|
|
@ -17,11 +17,14 @@ extern crate network;
|
|||
extern crate p2p;
|
||||
extern crate sync;
|
||||
extern crate import;
|
||||
extern crate rpc as ethcore_rpc;
|
||||
|
||||
mod commands;
|
||||
mod config;
|
||||
mod seednodes;
|
||||
mod util;
|
||||
mod rpc;
|
||||
mod rpc_apis;
|
||||
|
||||
use app_dirs::AppInfo;
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
use std::net::SocketAddr;
|
||||
use rpc_apis::{self, ApiSet};
|
||||
use ethcore_rpc::{Server, RpcServer, RpcServerError};
|
||||
use std::io;
|
||||
use sync;
|
||||
|
||||
pub struct Dependencies {
|
||||
pub local_sync_node: sync::LocalNodeRef,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct HttpConfiguration {
|
||||
pub enabled: bool,
|
||||
pub interface: String,
|
||||
pub port: u16,
|
||||
pub apis: ApiSet,
|
||||
pub cors: Option<Vec<String>>,
|
||||
pub hosts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl HttpConfiguration {
|
||||
pub fn with_port(port: u16) -> Self {
|
||||
HttpConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: port,
|
||||
apis: ApiSet::default(),
|
||||
cors: None,
|
||||
hosts: Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_http(conf: HttpConfiguration, deps: Dependencies) -> Result<Option<Server>, String> {
|
||||
if !conf.enabled {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let url = format!("{}:{}", conf.interface, conf.port);
|
||||
let addr = try!(url.parse().map_err(|_| format!("Invalid JSONRPC listen host/port given: {}", url)));
|
||||
Ok(Some(try!(setup_http_rpc_server(&addr, conf.cors, conf.hosts, conf.apis, deps))))
|
||||
}
|
||||
|
||||
pub fn setup_http_rpc_server(
|
||||
url: &SocketAddr,
|
||||
cors_domains: Option<Vec<String>>,
|
||||
allowed_hosts: Option<Vec<String>>,
|
||||
apis: ApiSet,
|
||||
deps: Dependencies,
|
||||
) -> Result<Server, String> {
|
||||
let server = try!(setup_rpc_server(apis, deps));
|
||||
// TODO: PanicsHandler
|
||||
let start_result = server.start_http(url, cors_domains, allowed_hosts);
|
||||
match start_result {
|
||||
Err(RpcServerError::IoError(err)) => match err.kind() {
|
||||
io::ErrorKind::AddrInUse => Err(format!("RPC address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options.", url)),
|
||||
_ => Err(format!("RPC io error: {}", err)),
|
||||
},
|
||||
Err(e) => Err(format!("RPC error: {:?}", e)),
|
||||
Ok(server) => Ok(server),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rpc_server(apis: ApiSet, deps: Dependencies) -> Result<RpcServer, String> {
|
||||
let server = RpcServer::new();
|
||||
Ok(rpc_apis::setup_rpc(server, apis, deps))
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
use std::str::FromStr;
|
||||
use std::collections::HashSet;
|
||||
use rpc::Dependencies;
|
||||
use ethcore_rpc::Extendable;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
pub enum Api {
|
||||
/// Raw
|
||||
Raw,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ApiSet {
|
||||
List(HashSet<Api>),
|
||||
}
|
||||
|
||||
impl Default for ApiSet {
|
||||
fn default() -> Self {
|
||||
ApiSet::List(vec![Api::Raw].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Api {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"raw" => Ok(Api::Raw),
|
||||
api => Err(format!("Unknown api: {}", api)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ApiSet {
|
||||
pub fn list_apis(&self) -> HashSet<Api> {
|
||||
match *self {
|
||||
ApiSet::List(ref apis) => apis.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_rpc<T: Extendable>(server: T, apis: ApiSet, deps: Dependencies) -> T {
|
||||
use ethcore_rpc::v1::*;
|
||||
|
||||
for api in apis.list_apis() {
|
||||
match api {
|
||||
Api::Raw => server.add_delegate(RawClient::new(RawClientCore::new(deps.local_sync_node.clone())).to_delegate()),
|
||||
}
|
||||
}
|
||||
server
|
||||
}
|
|
@ -124,6 +124,10 @@ macro_rules! impl_hash {
|
|||
impl Eq for $name { }
|
||||
|
||||
impl $name {
|
||||
pub fn take(self) -> [u8; $size] {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn reversed(&self) -> Self {
|
||||
let mut result = self.clone();
|
||||
result.reverse();
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "rpc"
|
||||
version = "0.1.0"
|
||||
authors = ["Ethcore <admin@ethcore.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
serde = "0.8"
|
||||
serde_json = "0.8"
|
||||
rustc-serialize = "0.3"
|
||||
tokio-core = "0.1.1"
|
||||
serde_macros = { version = "0.8.0", optional = true }
|
||||
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
|
||||
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
|
||||
sync = { path = "../sync" }
|
||||
serialization = { path = "../serialization" }
|
||||
chain = { path = "../chain" }
|
||||
primitives = { path = "../primitives" }
|
||||
p2p = { path = "../p2p" }
|
||||
network = { path = "../network" }
|
||||
db = { path = "../db" }
|
||||
test-data = { path = "../test-data" }
|
||||
|
||||
[build-dependencies]
|
||||
serde_codegen = { version = "0.8.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["serde_codegen"]
|
||||
nightly = ["serde_macros"]
|
|
@ -0,0 +1,25 @@
|
|||
#[cfg(not(feature = "serde_macros"))]
|
||||
mod inner {
|
||||
extern crate serde_codegen;
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
|
||||
let src = Path::new("src/v1/types/mod.rs.in");
|
||||
let dst = Path::new(&out_dir).join("mod.rs");
|
||||
|
||||
serde_codegen::expand(&src, &dst).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde_macros")]
|
||||
mod inner {
|
||||
pub fn main() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
inner::main();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#![cfg_attr(feature="nightly", plugin(serde_macros))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate rustc_serialize;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate jsonrpc_core;
|
||||
extern crate jsonrpc_http_server;
|
||||
extern crate tokio_core;
|
||||
extern crate sync;
|
||||
extern crate chain;
|
||||
extern crate serialization as ser;
|
||||
extern crate primitives;
|
||||
extern crate p2p;
|
||||
extern crate network;
|
||||
extern crate db;
|
||||
extern crate test_data;
|
||||
|
||||
pub mod v1;
|
||||
pub mod rpc_server;
|
||||
|
||||
pub use jsonrpc_http_server::{Server, RpcServerError};
|
||||
pub use self::rpc_server::{RpcServer, Extendable};
|
|
@ -0,0 +1,56 @@
|
|||
// TODO: panic handler
|
||||
use std::sync::Arc;
|
||||
use std::net::SocketAddr;
|
||||
use jsonrpc_core::{IoHandler, IoDelegate};
|
||||
use jsonrpc_http_server::{self, ServerBuilder, Server, RpcServerError};
|
||||
|
||||
/// An object that can be extended with `IoDelegates`
|
||||
pub trait Extendable {
|
||||
/// Add `Delegate` to this object.
|
||||
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>);
|
||||
}
|
||||
|
||||
/// Http server.
|
||||
pub struct RpcServer {
|
||||
handler: Arc<IoHandler>,
|
||||
}
|
||||
|
||||
impl Extendable for RpcServer {
|
||||
/// Add io delegate.
|
||||
fn add_delegate<D: Send + Sync + 'static>(&self, delegate: IoDelegate<D>) {
|
||||
self.handler.add_delegate(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcServer {
|
||||
/// Construct new http server object.
|
||||
pub fn new() -> RpcServer {
|
||||
RpcServer {
|
||||
handler: Arc::new(IoHandler::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Start http server asynchronously and returns result with `Server` handle on success or an error.
|
||||
pub fn start_http(
|
||||
&self,
|
||||
addr: &SocketAddr,
|
||||
cors_domains: Option<Vec<String>>,
|
||||
allowed_hosts: Option<Vec<String>>,
|
||||
) -> Result<Server, RpcServerError> {
|
||||
|
||||
let cors_domains = cors_domains.map(|domains| {
|
||||
domains.into_iter()
|
||||
.map(|v| match v.as_str() {
|
||||
"*" => jsonrpc_http_server::AccessControlAllowOrigin::Any,
|
||||
"null" => jsonrpc_http_server::AccessControlAllowOrigin::Null,
|
||||
v => jsonrpc_http_server::AccessControlAllowOrigin::Value(v.into()),
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
ServerBuilder::new(self.handler.clone())
|
||||
.cors(cors_domains.into())
|
||||
.allowed_hosts(allowed_hosts.into())
|
||||
.start_http(addr)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
// because we reuse the type names as idents in the macros as a dirty hack to
|
||||
// work around `concat_idents!` being unstable.
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
///! Automatically serialize and deserialize parameters around a strongly-typed function.
|
||||
|
||||
use super::errors;
|
||||
|
||||
use jsonrpc_core::{Error, Params, Value, from_params, to_value};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Auto-generates an RPC trait from trait definition.
|
||||
///
|
||||
/// This just copies out all the methods, docs, and adds another
|
||||
/// function `to_delegate` which will automatically wrap each strongly-typed
|
||||
/// function in a wrapper which handles parameter and output type serialization.
|
||||
///
|
||||
/// RPC functions may come in a couple forms: async and synchronous.
|
||||
/// These are parsed with the custom `#[rpc]` attribute, which must follow
|
||||
/// documentation.
|
||||
///
|
||||
/// ## The #[rpc] attribute
|
||||
///
|
||||
/// Valid forms:
|
||||
/// - `#[rpc(name = "name_here")]` (a synchronous rpc function which should be bound to the given name)
|
||||
/// - `#[rpc(async, name = "name_here")]` (an async rpc function which should be bound to the given name)
|
||||
///
|
||||
/// Synchronous function format:
|
||||
/// `fn foo(&self, Param1, Param2, Param3) -> Out`.
|
||||
///
|
||||
/// Asynchronous RPC functions must come in this form:
|
||||
/// `fn foo(&self, Param1, Param2, Param3, Ready<Out>);
|
||||
///
|
||||
/// Anything else will be rejected by the code generator.
|
||||
macro_rules! build_rpc_trait {
|
||||
// entry-point. todo: make another for traits w/ bounds.
|
||||
(
|
||||
$(#[$t_attr: meta])*
|
||||
pub trait $name: ident {
|
||||
$(
|
||||
$( #[doc=$m_doc:expr] )*
|
||||
#[ rpc( $($t:tt)* ) ]
|
||||
fn $m_name: ident ( $($p: tt)* ) $( -> Result<$out: ty, Error> )* ;
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(#[$t_attr])*
|
||||
pub trait $name: Sized + Send + Sync + 'static {
|
||||
$(
|
||||
$(#[doc=$m_doc])*
|
||||
fn $m_name ( $($p)* ) $( -> Result<$out, Error> )* ;
|
||||
)*
|
||||
|
||||
/// Transform this into an `IoDelegate`, automatically wrapping
|
||||
/// the parameters.
|
||||
fn to_delegate(self) -> ::jsonrpc_core::IoDelegate<Self> {
|
||||
let mut del = ::jsonrpc_core::IoDelegate::new(self.into());
|
||||
$(
|
||||
build_rpc_trait!(WRAP del =>
|
||||
( $($t)* )
|
||||
fn $m_name ( $($p)* ) $( -> Result<$out, Error> )*
|
||||
);
|
||||
)*
|
||||
del
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
( WRAP $del: expr =>
|
||||
(name = $name: expr)
|
||||
fn $method: ident (&self $(, $param: ty)*) -> Result<$out: ty, Error>
|
||||
) => {
|
||||
$del.add_method($name, move |base, params| {
|
||||
(Self::$method as fn(&_ $(, $param)*) -> Result<$out, Error>).wrap_rpc(base, params)
|
||||
})
|
||||
};
|
||||
|
||||
( WRAP $del: expr =>
|
||||
(async, name = $name: expr)
|
||||
fn $method: ident (&self, Ready<$out: ty> $(, $param: ty)*)
|
||||
) => {
|
||||
$del.add_async_method($name, move |base, params, ready| {
|
||||
(Self::$method as fn(&_, Ready<$out> $(, $param)*)).wrap_rpc(base, params, ready)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
/// A wrapper type without an implementation of `Deserialize`
|
||||
/// which allows a special implementation of `Wrap` for functions
|
||||
/// that take a trailing default parameter.
|
||||
pub struct Trailing<T: Default + Deserialize>(pub T);
|
||||
|
||||
/// A wrapper type for `jsonrpc_core`'s weakly-typed `Ready` struct.
|
||||
pub struct Ready<T: Serialize> {
|
||||
inner: ::jsonrpc_core::Ready,
|
||||
_marker: ::std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Serialize> From<::jsonrpc_core::Ready> for Ready<T> {
|
||||
fn from(ready: ::jsonrpc_core::Ready) -> Self {
|
||||
Ready { inner: ready, _marker: ::std::marker::PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize> Ready<T> {
|
||||
/// Respond withthe asynchronous result.
|
||||
pub fn ready(self, result: Result<T, Error>) {
|
||||
self.inner.ready(result.map(to_value))
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper trait for synchronous RPC functions.
|
||||
pub trait Wrap<B: Send + Sync + 'static> {
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error>;
|
||||
}
|
||||
|
||||
/// Wrapper trait for asynchronous RPC functions.
|
||||
pub trait WrapAsync<B: Send + Sync + 'static> {
|
||||
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready);
|
||||
}
|
||||
|
||||
// special impl for no parameters.
|
||||
impl<B, OUT> Wrap<B> for fn(&B) -> Result<OUT, Error>
|
||||
where B: Send + Sync + 'static, OUT: Serialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
|
||||
::v1::helpers::params::expect_no_params(params)
|
||||
.and_then(|()| (self)(base))
|
||||
.map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, OUT> WrapAsync<B> for fn(&B, Ready<OUT>)
|
||||
where B: Send + Sync + 'static, OUT: Serialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready) {
|
||||
match ::v1::helpers::params::expect_no_params(params) {
|
||||
Ok(()) => (self)(base, ready.into()),
|
||||
Err(e) => ready.ready(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// creates a wrapper implementation which deserializes the parameters,
|
||||
// calls the function with concrete type, and serializes the output.
|
||||
macro_rules! wrap {
|
||||
($($x: ident),+) => {
|
||||
|
||||
// synchronous implementation
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
> Wrap<BASE> for fn(&BASE, $($x,)+) -> Result<OUT, Error> {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
|
||||
from_params::<($($x,)+)>(params).and_then(|($($x,)+)| {
|
||||
(self)(base, $($x,)+)
|
||||
}).map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
// asynchronous implementation
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
> WrapAsync<BASE> for fn(&BASE, Ready<OUT>, $($x,)+ ) {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params, ready: ::jsonrpc_core::Ready) {
|
||||
match from_params::<($($x,)+)>(params) {
|
||||
Ok(($($x,)+)) => (self)(base, ready.into(), $($x,)+),
|
||||
Err(e) => ready.ready(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special impl for no parameters other than block parameter.
|
||||
impl<B, OUT, T> Wrap<B> for fn(&B, Trailing<T>) -> Result<OUT, Error>
|
||||
where B: Send + Sync + 'static, OUT: Serialize, T: Default + Deserialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params) -> Result<Value, Error> {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return Err(errors::invalid_params("not an array", "")),
|
||||
};
|
||||
|
||||
let (id,) = match len {
|
||||
0 => (T::default(),),
|
||||
1 => try!(from_params::<(T,)>(params)),
|
||||
_ => return Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
(self)(base, Trailing(id)).map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, OUT, T> WrapAsync<B> for fn(&B, Ready<OUT>, Trailing<T>)
|
||||
where B: Send + Sync + 'static, OUT: Serialize, T: Default + Deserialize
|
||||
{
|
||||
fn wrap_rpc(&self, base: &B, params: Params, ready: ::jsonrpc_core::Ready) {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return ready.ready(Err(errors::invalid_params("not an array", ""))),
|
||||
};
|
||||
|
||||
let id = match len {
|
||||
0 => Ok((T::default(),)),
|
||||
1 => from_params::<(T,)>(params),
|
||||
_ => Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
match id {
|
||||
Ok((id,)) => (self)(base, ready.into(), Trailing(id)),
|
||||
Err(e) => ready.ready(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// similar to `wrap!`, but handles a single default trailing parameter
|
||||
// accepts an additional argument indicating the number of non-trailing parameters.
|
||||
macro_rules! wrap_with_trailing {
|
||||
($num: expr, $($x: ident),+) => {
|
||||
// synchronous implementation
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
TRAILING: Default + Deserialize,
|
||||
> Wrap<BASE> for fn(&BASE, $($x,)+ Trailing<TRAILING>) -> Result<OUT, Error> {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params) -> Result<Value, Error> {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return Err(errors::invalid_params("not an array", "")),
|
||||
};
|
||||
|
||||
let params = match len - $num {
|
||||
0 => from_params::<($($x,)+)>(params)
|
||||
.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
|
||||
1 => from_params::<($($x,)+ TRAILING)>(params)
|
||||
.map(|($($x,)+ id)| ($($x,)+ id)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
let ($($x,)+ id) = try!(params);
|
||||
(self)(base, $($x,)+ Trailing(id)).map(to_value)
|
||||
}
|
||||
}
|
||||
|
||||
// asynchronous implementation
|
||||
impl <
|
||||
BASE: Send + Sync + 'static,
|
||||
OUT: Serialize,
|
||||
$($x: Deserialize,)+
|
||||
TRAILING: Default + Deserialize,
|
||||
> WrapAsync<BASE> for fn(&BASE, Ready<OUT>, $($x,)+ Trailing<TRAILING>) {
|
||||
fn wrap_rpc(&self, base: &BASE, params: Params, ready: ::jsonrpc_core::Ready) {
|
||||
let len = match params {
|
||||
Params::Array(ref v) => v.len(),
|
||||
Params::None => 0,
|
||||
_ => return ready.ready(Err(errors::invalid_params("not an array", ""))),
|
||||
};
|
||||
|
||||
let params = match len - $num {
|
||||
0 => from_params::<($($x,)+)>(params)
|
||||
.map(|($($x,)+)| ($($x,)+ TRAILING::default())),
|
||||
1 => from_params::<($($x,)+ TRAILING)>(params)
|
||||
.map(|($($x,)+ id)| ($($x,)+ id)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
};
|
||||
|
||||
match params {
|
||||
Ok(($($x,)+ id)) => (self)(base, ready.into(), $($x,)+ Trailing(id)),
|
||||
Err(e) => ready.ready(Err(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrap!(A, B, C, D, E);
|
||||
wrap!(A, B, C, D);
|
||||
wrap!(A, B, C);
|
||||
wrap!(A, B);
|
||||
wrap!(A);
|
||||
|
||||
wrap_with_trailing!(5, A, B, C, D, E);
|
||||
wrap_with_trailing!(4, A, B, C, D);
|
||||
wrap_with_trailing!(3, A, B, C);
|
||||
wrap_with_trailing!(2, A, B);
|
||||
wrap_with_trailing!(1, A);
|
|
@ -0,0 +1,38 @@
|
|||
///! RPC Error codes and error objects
|
||||
|
||||
mod codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
pub const EXECUTION_ERROR: i64 = -32015;
|
||||
}
|
||||
|
||||
|
||||
macro_rules! rpc_unimplemented {
|
||||
() => (Err(::v1::helpers::errors::unimplemented(None)))
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
use jsonrpc_core::{Error, ErrorCode, Value};
|
||||
|
||||
pub fn unimplemented(details: Option<String>) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::InternalError,
|
||||
message: "This request is not implemented yet. Please create an issue on Github repo.".into(),
|
||||
data: details.map(Value::String),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid_params<T: fmt::Debug>(param: &str, details: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::InvalidParams,
|
||||
message: format!("Couldn't parse parameters: {}", param),
|
||||
data: Some(Value::String(format!("{:?}", details))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execution<T: fmt::Debug>(data: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::EXECUTION_ERROR),
|
||||
message: "Execution error.".into(),
|
||||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#[macro_use]
|
||||
pub mod auto_args;
|
||||
#[macro_use]
|
||||
pub mod errors;
|
||||
mod params;
|
|
@ -0,0 +1,11 @@
|
|||
///! Parameters parsing helpers
|
||||
|
||||
use jsonrpc_core::{Error, Params};
|
||||
use v1::helpers::errors;
|
||||
|
||||
pub fn expect_no_params(params: Params) -> Result<(), Error> {
|
||||
match params {
|
||||
Params::None => Ok(()),
|
||||
p => Err(errors::invalid_params("No parameters were expected", p)),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
mod raw;
|
||||
|
||||
pub use self::raw::{RawClient, RawClientCore};
|
|
@ -0,0 +1,117 @@
|
|||
use v1::traits::Raw;
|
||||
use v1::types::RawTransaction;
|
||||
use v1::types::H256;
|
||||
use v1::helpers::errors::{execution, invalid_params};
|
||||
use jsonrpc_core::Error;
|
||||
use chain::Transaction;
|
||||
use sync;
|
||||
use ser::{Reader, deserialize};
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
|
||||
pub struct RawClient<T: RawClientCoreApi> {
|
||||
core: T,
|
||||
}
|
||||
|
||||
pub trait RawClientCoreApi: Send + Sync + 'static {
|
||||
fn accept_transaction(&self, transaction: Transaction) -> Result<GlobalH256, String>;
|
||||
}
|
||||
|
||||
pub struct RawClientCore {
|
||||
local_sync_node: sync::LocalNodeRef,
|
||||
}
|
||||
|
||||
impl RawClientCore {
|
||||
pub fn new(local_sync_node: sync::LocalNodeRef) -> Self {
|
||||
RawClientCore {
|
||||
local_sync_node: local_sync_node,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawClientCoreApi for RawClientCore {
|
||||
fn accept_transaction(&self, transaction: Transaction) -> Result<GlobalH256, String> {
|
||||
self.local_sync_node.accept_transaction(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> RawClient<T> where T: RawClientCoreApi {
|
||||
pub fn new(core: T) -> Self {
|
||||
RawClient {
|
||||
core: core,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Raw for RawClient<T> where T: RawClientCoreApi {
|
||||
fn send_raw_transaction(&self, raw_transaction: RawTransaction) -> Result<H256, Error> {
|
||||
let raw_transaction_data: Vec<u8> = raw_transaction.into();
|
||||
let transaction = try!(deserialize(Reader::new(&raw_transaction_data)).map_err(|e| invalid_params("tx", e)));
|
||||
self.core.accept_transaction(transaction)
|
||||
.map(|h| h.reversed().into())
|
||||
.map_err(|e| execution(e))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use jsonrpc_core::{IoHandler, GenericIoHandler};
|
||||
use chain::Transaction;
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
use v1::traits::Raw;
|
||||
use super::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct SuccessRawClientCore;
|
||||
#[derive(Default)]
|
||||
struct ErrorRawClientCore;
|
||||
|
||||
impl RawClientCoreApi for SuccessRawClientCore {
|
||||
fn accept_transaction(&self, transaction: Transaction) -> Result<GlobalH256, String> {
|
||||
Ok(transaction.hash())
|
||||
}
|
||||
}
|
||||
|
||||
impl RawClientCoreApi for ErrorRawClientCore {
|
||||
fn accept_transaction(&self, _transaction: Transaction) -> Result<GlobalH256, String> {
|
||||
Err("error".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sendrawtransaction_accepted() {
|
||||
let client = RawClient::new(SuccessRawClientCore::default());
|
||||
let handler = IoHandler::new();
|
||||
handler.add_delegate(client.to_delegate());
|
||||
|
||||
let sample = handler.handle_request_sync(&(r#"
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "sendrawtransaction",
|
||||
"params": ["00000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a0000000000000000000101000000000000000000000000"],
|
||||
"id": 1
|
||||
}"#)
|
||||
).unwrap();
|
||||
|
||||
// direct hash is 0791efccd035c5fe501023ff888106eba5eff533965de4a6e06400f623bcac34
|
||||
// but client expects reverse hash
|
||||
assert_eq!(r#"{"jsonrpc":"2.0","result":"34acbc23f60064e0a6e45d9633f5efa5eb068188ff231050fec535d0ccef9107","id":1}"#, &sample);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sendrawtransaction_rejected() {
|
||||
let client = RawClient::new(ErrorRawClientCore::default());
|
||||
let handler = IoHandler::new();
|
||||
handler.add_delegate(client.to_delegate());
|
||||
|
||||
let sample = handler.handle_request_sync(&(r#"
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "sendrawtransaction",
|
||||
"params": ["00000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a0000000000000000000101000000000000000000000000"],
|
||||
"id": 1
|
||||
}"#)
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(r#"{"jsonrpc":"2.0","error":{"code":-32015,"message":"Execution error.","data":"\"error\""},"id":1}"#, &sample);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
#[macro_use]
|
||||
pub mod helpers;
|
||||
pub mod impls;
|
||||
pub mod traits;
|
||||
pub mod types;
|
||||
|
||||
pub use self::traits::Raw;
|
||||
pub use self::impls::{RawClient, RawClientCore};
|
|
@ -0,0 +1,3 @@
|
|||
mod raw;
|
||||
|
||||
pub use self::raw::Raw;
|
|
@ -0,0 +1,14 @@
|
|||
use jsonrpc_core::Error;
|
||||
|
||||
use v1::helpers::auto_args::Wrap;
|
||||
use v1::types::RawTransaction;
|
||||
use v1::types::H256;
|
||||
|
||||
build_rpc_trait! {
|
||||
/// Partiy-bitcoin raw data interface.
|
||||
pub trait Raw {
|
||||
/// Adds transaction to the memory pool && relays it to the peers.
|
||||
#[rpc(name = "sendrawtransaction")]
|
||||
fn send_raw_transaction(&self, RawTransaction) -> Result<H256, Error>;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
///! Serializable wrapper around vector of bytes
|
||||
use rustc_serialize::hex::{ToHex, FromHex};
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error};
|
||||
use serde::de::Visitor;
|
||||
|
||||
/// Wrapper structure around vector of bytes.
|
||||
#[derive(Debug, PartialEq, Eq, Default, Hash, Clone)]
|
||||
pub struct Bytes(pub Vec<u8>);
|
||||
|
||||
impl Bytes {
|
||||
/// Simple constructor.
|
||||
pub fn new(bytes: Vec<u8>) -> Bytes {
|
||||
Bytes(bytes)
|
||||
}
|
||||
|
||||
/// Convert back to vector
|
||||
pub fn to_vec(self) -> Vec<u8> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Bytes {
|
||||
fn from(bytes: Vec<u8>) -> Bytes {
|
||||
Bytes(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for Bytes {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Bytes {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: Serializer {
|
||||
let mut serialized = String::new();
|
||||
serialized.push_str(self.0.to_hex().as_ref());
|
||||
serializer.serialize_str(serialized.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for Bytes {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<Bytes, D::Error>
|
||||
where D: Deserializer {
|
||||
deserializer.deserialize(BytesVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct BytesVisitor;
|
||||
|
||||
impl Visitor for BytesVisitor {
|
||||
type Value = Bytes;
|
||||
|
||||
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: Error {
|
||||
if value.len() > 0 && value.len() & 1 == 0 {
|
||||
Ok(Bytes::new(try!(FromHex::from_hex(&value).map_err(|_| Error::custom("invalid hex")))))
|
||||
} else {
|
||||
Err(Error::custom("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: Error {
|
||||
self.visit_str(value.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
|
||||
#[test]
|
||||
fn test_bytes_serialize() {
|
||||
let bytes = Bytes("0123456789abcdef".from_hex().unwrap());
|
||||
let serialized = serde_json::to_string(&bytes).unwrap();
|
||||
assert_eq!(serialized, r#""0123456789abcdef""#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytes_deserialize() {
|
||||
let bytes1: Result<Bytes, serde_json::Error> = serde_json::from_str(r#""""#);
|
||||
let bytes2: Result<Bytes, serde_json::Error> = serde_json::from_str(r#""123""#);
|
||||
let bytes3: Result<Bytes, serde_json::Error> = serde_json::from_str(r#""gg""#);
|
||||
|
||||
let bytes4: Bytes = serde_json::from_str(r#""12""#).unwrap();
|
||||
let bytes5: Bytes = serde_json::from_str(r#""0123""#).unwrap();
|
||||
|
||||
assert!(bytes1.is_err());
|
||||
assert!(bytes2.is_err());
|
||||
assert!(bytes3.is_err());
|
||||
assert_eq!(bytes4, Bytes(vec![0x12]));
|
||||
assert_eq!(bytes5, Bytes(vec![0x1, 0x23]));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use serde;
|
||||
use rustc_serialize::hex::{ToHex, FromHex};
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
|
||||
macro_rules! impl_hash {
|
||||
($name: ident, $other: ident, $size: expr) => {
|
||||
/// Hash serialization
|
||||
#[derive(Eq)]
|
||||
pub struct $name([u8; $size]);
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
$name([0; $size])
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "{}", $other::from(self.0.clone()).to_hex())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for $name where $other: From<T> {
|
||||
fn from(o: T) -> Self {
|
||||
$name($other::from(o).take())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for $name {
|
||||
type Err = <$other as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let other = try!($other::from_str(s));
|
||||
Ok($name(other.take()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<$other> for $name {
|
||||
fn into(self) -> $other {
|
||||
$other::from(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for $name {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let self_ref: &[u8] = &self.0;
|
||||
let other_ref: &[u8] = &other.0;
|
||||
self_ref == other_ref
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for $name {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
let self_ref: &[u8] = &self.0;
|
||||
let other_ref: &[u8] = &other.0;
|
||||
self_ref.partial_cmp(other_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $name {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let self_ref: &[u8] = &self.0;
|
||||
let other_ref: &[u8] = &other.0;
|
||||
self_ref.cmp(other_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for $name {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
$other::from(self.0.clone()).hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for $name {
|
||||
fn clone(&self) -> Self {
|
||||
let mut r = [0; $size];
|
||||
r.copy_from_slice(&self.0);
|
||||
$name(r)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for $name {
|
||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||
where S: serde::Serializer {
|
||||
let mut hex = String::new();
|
||||
hex.push_str(&$other::from(self.0.clone()).to_hex());
|
||||
serializer.serialize_str(&hex)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Deserialize for $name {
|
||||
fn deserialize<D>(deserializer: &mut D) -> Result<$name, D::Error> where D: serde::Deserializer {
|
||||
struct HashVisitor;
|
||||
|
||||
impl serde::de::Visitor for HashVisitor {
|
||||
type Value = $name;
|
||||
|
||||
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: serde::Error {
|
||||
|
||||
if value.len() != $size * 2 {
|
||||
return Err(serde::Error::custom("Invalid length."));
|
||||
}
|
||||
|
||||
match value[..].from_hex() {
|
||||
Ok(ref v) => {
|
||||
let mut result = [0u8; $size];
|
||||
result.copy_from_slice(v);
|
||||
Ok($name($other::from(result).take()))
|
||||
},
|
||||
_ => Err(serde::Error::custom("Invalid hex value."))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: serde::Error {
|
||||
self.visit_str(value.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize(HashVisitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_hash!(H256, GlobalH256, 32);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::H256;
|
||||
use primitives::hash::H256 as GlobalH256;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn hash_debug() {
|
||||
let str_reversed = "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048";
|
||||
let reversed_hash = H256::from(str_reversed);
|
||||
let debug_result = format!("{:?}", reversed_hash);
|
||||
assert_eq!(debug_result, str_reversed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_from_str() {
|
||||
let str_reversed = "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048";
|
||||
match H256::from_str(str_reversed) {
|
||||
Ok(reversed_hash) => assert_eq!(format!("{:?}", reversed_hash), str_reversed),
|
||||
_ => panic!("unexpected"),
|
||||
}
|
||||
|
||||
let str_reversed = "XXXYYY";
|
||||
match H256::from_str(str_reversed) {
|
||||
Ok(_) => panic!("unexpected"),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_to_global_hash() {
|
||||
let str_reversed = "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048";
|
||||
let reversed_hash = H256::from(str_reversed);
|
||||
let global_hash = GlobalH256::from(str_reversed);
|
||||
let global_converted: GlobalH256 = reversed_hash.into();
|
||||
assert_eq!(global_converted, global_hash);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
///! Structures used in RPC communication
|
||||
|
||||
#[cfg(feature = "serde_macros")]
|
||||
include!("mod.rs.in");
|
||||
|
||||
#[cfg(not(feature = "serde_macros"))]
|
||||
include!(concat!(env!("OUT_DIR"), "/mod.rs"));
|
|
@ -0,0 +1,7 @@
|
|||
mod bytes;
|
||||
mod hash;
|
||||
mod raw_transaction;
|
||||
|
||||
pub use self::bytes::Bytes;
|
||||
pub use self::hash::H256;
|
||||
pub use self::raw_transaction::RawTransaction;
|
|
@ -0,0 +1,3 @@
|
|||
use super::bytes::Bytes;
|
||||
|
||||
pub type RawTransaction = Bytes;
|
|
@ -5,7 +5,8 @@ use chain;
|
|||
use db;
|
||||
use network::Magic;
|
||||
use orphan_blocks_pool::OrphanBlocksPool;
|
||||
use synchronization_verifier::{Verifier, SyncVerifier, VerificationSink, VerificationTask};
|
||||
use synchronization_verifier::{Verifier, SyncVerifier, VerificationTask,
|
||||
VerificationSink, BlockVerificationSink, TransactionVerificationSink};
|
||||
use primitives::hash::H256;
|
||||
use super::Error;
|
||||
|
||||
|
@ -15,28 +16,37 @@ pub struct BlocksWriter {
|
|||
storage: db::SharedStore,
|
||||
orphaned_blocks_pool: OrphanBlocksPool,
|
||||
verifier: SyncVerifier<BlocksWriterSink>,
|
||||
sink: Arc<Mutex<BlocksWriterSink>>,
|
||||
sink: Arc<BlocksWriterSinkData>,
|
||||
}
|
||||
|
||||
struct BlocksWriterSink {
|
||||
data: Arc<BlocksWriterSinkData>,
|
||||
}
|
||||
|
||||
struct BlocksWriterSinkData {
|
||||
storage: db::SharedStore,
|
||||
err: Option<Error>,
|
||||
err: Mutex<Option<Error>>,
|
||||
}
|
||||
|
||||
impl BlocksWriter {
|
||||
pub fn new(storage: db::SharedStore, network: Magic) -> BlocksWriter {
|
||||
let sink = Arc::new(Mutex::new(BlocksWriterSink::new(storage.clone())));
|
||||
let verifier = SyncVerifier::new(network, storage.clone(), sink.clone());
|
||||
let sink_data = Arc::new(BlocksWriterSinkData::new(storage.clone()));
|
||||
let sink = Arc::new(BlocksWriterSink::new(sink_data.clone()));
|
||||
let verifier = SyncVerifier::new(network, storage.clone(), sink);
|
||||
BlocksWriter {
|
||||
storage: storage,
|
||||
orphaned_blocks_pool: OrphanBlocksPool::new(),
|
||||
verifier: verifier,
|
||||
sink: sink,
|
||||
sink: sink_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_block(&mut self, block: chain::Block) -> Result<(), Error> {
|
||||
let indexed_block: db::IndexedBlock = block.into();
|
||||
// do not append block if it is already there
|
||||
if self.storage.contains_block(db::BlockRef::Hash(indexed_block.hash().clone())) {
|
||||
return Ok(());
|
||||
}
|
||||
// verify && insert only if parent block is already in the storage
|
||||
if !self.storage.contains_block(db::BlockRef::Hash(indexed_block.header().previous_header_hash.clone())) {
|
||||
self.orphaned_blocks_pool.insert_orphaned_block(indexed_block.hash().clone(), indexed_block);
|
||||
|
@ -52,7 +62,8 @@ impl BlocksWriter {
|
|||
verification_queue.push_front(indexed_block);
|
||||
while let Some(block) = verification_queue.pop_front() {
|
||||
self.verifier.verify_block(block);
|
||||
if let Some(err) = self.sink.lock().error() {
|
||||
|
||||
if let Some(err) = self.sink.error() {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
@ -62,35 +73,48 @@ impl BlocksWriter {
|
|||
}
|
||||
|
||||
impl BlocksWriterSink {
|
||||
pub fn new(storage: db::SharedStore) -> Self {
|
||||
pub fn new(data: Arc<BlocksWriterSinkData>) -> Self {
|
||||
BlocksWriterSink {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlocksWriterSinkData {
|
||||
pub fn new(storage: db::SharedStore) -> Self {
|
||||
BlocksWriterSinkData {
|
||||
storage: storage,
|
||||
err: None,
|
||||
err: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error(&mut self) -> Option<Error> {
|
||||
self.err.take()
|
||||
pub fn error(&self) -> Option<Error> {
|
||||
self.err.lock().take()
|
||||
}
|
||||
}
|
||||
|
||||
impl VerificationSink for BlocksWriterSink {
|
||||
fn on_block_verification_success(&mut self, block: db::IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
if let Err(err) = self.storage.insert_indexed_block(&block) {
|
||||
self.err = Some(Error::Database(err));
|
||||
}
|
||||
|
||||
impl BlockVerificationSink for BlocksWriterSink {
|
||||
fn on_block_verification_success(&self, block: db::IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
if let Err(err) = self.data.storage.insert_indexed_block(&block) {
|
||||
*self.data.err.lock() = Some(Error::Database(err));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn on_block_verification_error(&mut self, err: &str, _hash: &H256) {
|
||||
self.err = Some(Error::Verification(err.into()));
|
||||
fn on_block_verification_error(&self, err: &str, _hash: &H256) {
|
||||
*self.data.err.lock() = Some(Error::Verification(err.into()));
|
||||
}
|
||||
}
|
||||
|
||||
fn on_transaction_verification_success(&mut self, _transaction: chain::Transaction) {
|
||||
impl TransactionVerificationSink for BlocksWriterSink {
|
||||
fn on_transaction_verification_success(&self, _transaction: chain::Transaction) {
|
||||
unreachable!("not intended to verify transactions")
|
||||
}
|
||||
|
||||
fn on_transaction_verification_error(&mut self, _err: &str, _hash: &H256) {
|
||||
fn on_transaction_verification_error(&self, _err: &str, _hash: &H256) {
|
||||
unreachable!("not intended to verify transactions")
|
||||
}
|
||||
}
|
||||
|
@ -142,4 +166,16 @@ mod tests {
|
|||
};
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocks_writer_append_to_existing_db() {
|
||||
let db = Arc::new(db::TestStorage::with_genesis_block());
|
||||
let mut blocks_target = BlocksWriter::new(db.clone(), Magic::Testnet);
|
||||
|
||||
assert!(blocks_target.append_block(test_data::genesis()).is_ok());
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 0);
|
||||
|
||||
assert!(blocks_target.append_block(test_data::block_h1()).is_ok());
|
||||
assert_eq!(db.best_block().expect("Block is inserted").number, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ mod synchronization_peers;
|
|||
mod synchronization_server;
|
||||
mod synchronization_verifier;
|
||||
|
||||
pub use local_node::LocalNodeRef;
|
||||
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use tokio_core::reactor::Handle;
|
||||
|
@ -65,14 +67,13 @@ pub fn create_sync_blocks_writer(db: db::SharedStore, network: Magic) -> blocks_
|
|||
blocks_writer::BlocksWriter::new(db, network)
|
||||
}
|
||||
|
||||
/// Create inbound synchronization connections factory for given `db`.
|
||||
pub fn create_sync_connection_factory(handle: &Handle, network: Magic, db: db::SharedStore) -> p2p::LocalSyncNodeRef {
|
||||
/// Creates local sync node for given `db`
|
||||
pub fn create_local_sync_node(handle: &Handle, network: Magic, db: db::SharedStore) -> LocalNodeRef {
|
||||
use synchronization_chain::Chain as SyncChain;
|
||||
use synchronization_executor::LocalSynchronizationTaskExecutor as SyncExecutor;
|
||||
use local_node::LocalNode as SyncNode;
|
||||
use inbound_connection_factory::InboundConnectionFactory as SyncConnectionFactory;
|
||||
use synchronization_server::SynchronizationServer;
|
||||
use synchronization_client::{SynchronizationClient, SynchronizationClientCore, Config as SynchronizationConfig};
|
||||
use synchronization_client::{SynchronizationClient, SynchronizationClientCore, CoreVerificationSink, Config as SynchronizationConfig};
|
||||
use synchronization_verifier::AsyncVerifier;
|
||||
|
||||
let sync_client_config = SynchronizationConfig {
|
||||
|
@ -87,8 +88,15 @@ pub fn create_sync_connection_factory(handle: &Handle, network: Magic, db: db::S
|
|||
let sync_executor = SyncExecutor::new(sync_chain.clone());
|
||||
let sync_server = Arc::new(SynchronizationServer::new(sync_chain.clone(), sync_executor.clone()));
|
||||
let sync_client_core = SynchronizationClientCore::new(sync_client_config, handle, sync_executor.clone(), sync_chain.clone(), chain_verifier.clone());
|
||||
let verifier = AsyncVerifier::new(chain_verifier, sync_chain, sync_client_core.clone());
|
||||
let verifier_sink = Arc::new(CoreVerificationSink::new(sync_client_core.clone()));
|
||||
let verifier = AsyncVerifier::new(chain_verifier, sync_chain, verifier_sink);
|
||||
let sync_client = SynchronizationClient::new(sync_client_core, verifier);
|
||||
let sync_node = Arc::new(SyncNode::new(sync_server, sync_client, sync_executor));
|
||||
SyncConnectionFactory::with_local_node(sync_node)
|
||||
Arc::new(SyncNode::new(sync_server, sync_client, sync_executor))
|
||||
}
|
||||
|
||||
/// Create inbound synchronization connections factory for given local sync node.
|
||||
pub fn create_sync_connection_factory(local_sync_node: LocalNodeRef) -> p2p::LocalSyncNodeRef {
|
||||
use inbound_connection_factory::InboundConnectionFactory as SyncConnectionFactory;
|
||||
|
||||
SyncConnectionFactory::with_local_node(local_sync_node)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::{Mutex, Condvar};
|
||||
use db;
|
||||
use chain::Transaction;
|
||||
use p2p::OutboundSyncConnectionRef;
|
||||
use message::common::{InventoryType, InventoryVector};
|
||||
use message::types;
|
||||
use synchronization_client::{Client, SynchronizationClient, BlockAnnouncementType};
|
||||
use synchronization_executor::{Task as SynchronizationTask, TaskExecutor as SynchronizationTaskExecutor, LocalSynchronizationTaskExecutor};
|
||||
use synchronization_server::{Server, SynchronizationServer};
|
||||
use synchronization_verifier::AsyncVerifier;
|
||||
use synchronization_verifier::{AsyncVerifier, TransactionVerificationSink};
|
||||
use primitives::hash::H256;
|
||||
|
||||
// TODO: check messages before processing (filterload' filter is max 36000, nHashFunc is <= 50, etc)
|
||||
|
@ -35,6 +36,17 @@ pub trait PeersConnections {
|
|||
fn remove_peer_connection(&mut self, peer_index: usize);
|
||||
}
|
||||
|
||||
/// Transaction accept verification sink
|
||||
struct TransactionAcceptSink {
|
||||
data: Arc<TransactionAcceptSinkData>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TransactionAcceptSinkData {
|
||||
result: Mutex<Option<Result<H256, String>>>,
|
||||
waiter: Condvar,
|
||||
}
|
||||
|
||||
impl<T, U, V> LocalNode<T, U, V> where T: SynchronizationTaskExecutor + PeersConnections,
|
||||
U: Server,
|
||||
V: Client {
|
||||
|
@ -238,6 +250,18 @@ impl<T, U, V> LocalNode<T, U, V> where T: SynchronizationTaskExecutor + PeersCon
|
|||
self.client.lock().on_peer_blocks_notfound(peer_index, blocks_inventory);
|
||||
}
|
||||
|
||||
pub fn accept_transaction(&self, transaction: Transaction) -> Result<H256, String> {
|
||||
let sink_data = Arc::new(TransactionAcceptSinkData::default());
|
||||
let sink = TransactionAcceptSink::new(sink_data.clone()).boxed();
|
||||
{
|
||||
let mut client = self.client.lock();
|
||||
if let Err(err) = client.accept_transaction(transaction, sink) {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
sink_data.wait()
|
||||
}
|
||||
|
||||
fn transactions_inventory(&self, inventory: &[InventoryVector]) -> Vec<H256> {
|
||||
inventory.iter()
|
||||
.filter(|item| item.inv_type == InventoryType::MessageTx)
|
||||
|
@ -253,6 +277,42 @@ impl<T, U, V> LocalNode<T, U, V> where T: SynchronizationTaskExecutor + PeersCon
|
|||
}
|
||||
}
|
||||
|
||||
impl TransactionAcceptSink {
|
||||
pub fn new(data: Arc<TransactionAcceptSinkData>) -> Self {
|
||||
TransactionAcceptSink {
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn boxed(self) -> Box<Self> {
|
||||
Box::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionAcceptSinkData {
|
||||
pub fn wait(&self) -> Result<H256, String> {
|
||||
let mut lock = self.result.lock();
|
||||
if lock.is_some() {
|
||||
return lock.take().unwrap();
|
||||
}
|
||||
|
||||
self.waiter.wait(&mut lock);
|
||||
return lock.take().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionVerificationSink for TransactionAcceptSink {
|
||||
fn on_transaction_verification_success(&self, tx: Transaction) {
|
||||
*self.data.result.lock() = Some(Ok(tx.hash()));
|
||||
self.data.waiter.notify_all();
|
||||
}
|
||||
|
||||
fn on_transaction_verification_error(&self, err: &str, _hash: &H256) {
|
||||
*self.data.result.lock() = Some(Err(err.to_owned()));
|
||||
self.data.waiter.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
@ -260,12 +320,13 @@ mod tests {
|
|||
use connection_filter::tests::{default_filterload, make_filteradd};
|
||||
use synchronization_executor::Task;
|
||||
use synchronization_executor::tests::DummyTaskExecutor;
|
||||
use synchronization_client::{Config, SynchronizationClient, SynchronizationClientCore, FilteredInventory};
|
||||
use synchronization_client::{Config, SynchronizationClient, SynchronizationClientCore, CoreVerificationSink, FilteredInventory};
|
||||
use synchronization_chain::Chain;
|
||||
use p2p::{event_loop, OutboundSyncConnection, OutboundSyncConnectionRef};
|
||||
use message::types;
|
||||
use message::common::{InventoryVector, InventoryType, BlockTransactionsRequest};
|
||||
use network::Magic;
|
||||
use chain::Transaction;
|
||||
use db;
|
||||
use super::LocalNode;
|
||||
use test_data;
|
||||
|
@ -309,7 +370,7 @@ mod tests {
|
|||
fn close(&self) {}
|
||||
}
|
||||
|
||||
fn create_local_node() -> (Core, Handle, Arc<Mutex<DummyTaskExecutor>>, Arc<DummyServer>, LocalNode<DummyTaskExecutor, DummyServer, SynchronizationClient<DummyTaskExecutor, DummyVerifier>>) {
|
||||
fn create_local_node(verifier: Option<DummyVerifier>) -> (Core, Handle, Arc<Mutex<DummyTaskExecutor>>, Arc<DummyServer>, LocalNode<DummyTaskExecutor, DummyServer, SynchronizationClient<DummyTaskExecutor, DummyVerifier>>) {
|
||||
let event_loop = event_loop();
|
||||
let handle = event_loop.handle();
|
||||
let chain = Arc::new(RwLock::new(Chain::new(Arc::new(db::TestStorage::with_genesis_block()))));
|
||||
|
@ -318,8 +379,11 @@ mod tests {
|
|||
let config = Config { threads_num: 1, close_connection_on_bad_block: true };
|
||||
let chain_verifier = Arc::new(ChainVerifier::new(chain.read().storage(), Magic::Mainnet));
|
||||
let client_core = SynchronizationClientCore::new(config, &handle, executor.clone(), chain.clone(), chain_verifier);
|
||||
let mut verifier = DummyVerifier::default();
|
||||
verifier.set_sink(client_core.clone());
|
||||
let mut verifier = match verifier {
|
||||
Some(verifier) => verifier,
|
||||
None => DummyVerifier::default(),
|
||||
};
|
||||
verifier.set_sink(Arc::new(CoreVerificationSink::new(client_core.clone())));
|
||||
let client = SynchronizationClient::new(client_core, verifier);
|
||||
let local_node = LocalNode::new(server.clone(), client, executor.clone());
|
||||
(event_loop, handle, executor, server, local_node)
|
||||
|
@ -327,7 +391,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_request_inventory_on_sync_start() {
|
||||
let (_, _, executor, _, local_node) = create_local_node();
|
||||
let (_, _, executor, _, local_node) = create_local_node(None);
|
||||
let peer_index = local_node.create_sync_session(0, DummyOutboundSyncConnection::new());
|
||||
// start sync session
|
||||
local_node.start_sync_session(peer_index, 0);
|
||||
|
@ -338,7 +402,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_serves_block() {
|
||||
let (_, _, _, server, local_node) = create_local_node();
|
||||
let (_, _, _, server, local_node) = create_local_node(None);
|
||||
let peer_index = local_node.create_sync_session(0, DummyOutboundSyncConnection::new());
|
||||
// peer requests genesis block
|
||||
let genesis_block_hash = test_data::genesis().hash();
|
||||
|
@ -358,7 +422,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_serves_merkleblock() {
|
||||
let (_, _, _, server, local_node) = create_local_node();
|
||||
let (_, _, _, server, local_node) = create_local_node(None);
|
||||
|
||||
let genesis = test_data::genesis();
|
||||
let b1 = test_data::block_builder().header().parent(genesis.hash()).build()
|
||||
|
@ -458,7 +522,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_serves_compactblock() {
|
||||
let (_, _, _, server, local_node) = create_local_node();
|
||||
let (_, _, _, server, local_node) = create_local_node(None);
|
||||
|
||||
let genesis = test_data::genesis();
|
||||
let b1 = test_data::block_builder().header().parent(genesis.hash()).build()
|
||||
|
@ -490,7 +554,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_serves_get_block_txn_when_recently_sent_compact_block() {
|
||||
let (_, _, _, server, local_node) = create_local_node();
|
||||
let (_, _, _, server, local_node) = create_local_node(None);
|
||||
|
||||
let genesis = test_data::genesis();
|
||||
let b1 = test_data::block_builder().header().parent(genesis.hash()).build()
|
||||
|
@ -526,7 +590,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn local_node_not_serves_get_block_txn_when_compact_block_was_not_sent() {
|
||||
let (_, _, _, server, local_node) = create_local_node();
|
||||
let (_, _, _, server, local_node) = create_local_node(None);
|
||||
|
||||
let genesis = test_data::genesis();
|
||||
let b1 = test_data::block_builder().header().parent(genesis.hash()).build()
|
||||
|
@ -550,4 +614,49 @@ mod tests {
|
|||
let tasks = server.take_tasks();
|
||||
assert_eq!(tasks, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_node_accepts_local_transaction() {
|
||||
let (_, _, executor, _, local_node) = create_local_node(None);
|
||||
|
||||
// transaction will be relayed to this peer
|
||||
let peer_index1 = local_node.create_sync_session(0, DummyOutboundSyncConnection::new());
|
||||
{ executor.lock().take_tasks(); }
|
||||
|
||||
let genesis = test_data::genesis();
|
||||
let transaction: Transaction = test_data::TransactionBuilder::with_output(1).add_input(&genesis.transactions[0], 0).into();
|
||||
let transaction_hash = transaction.hash();
|
||||
|
||||
let result = local_node.accept_transaction(transaction);
|
||||
assert_eq!(result, Ok(transaction_hash));
|
||||
|
||||
assert_eq!(executor.lock().take_tasks(), vec![Task::SendInventory(peer_index1,
|
||||
vec![InventoryVector {
|
||||
inv_type: InventoryType::MessageTx,
|
||||
hash: "0791efccd035c5fe501023ff888106eba5eff533965de4a6e06400f623bcac34".into(),
|
||||
}]
|
||||
)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_node_discards_local_transaction() {
|
||||
let genesis = test_data::genesis();
|
||||
let transaction: Transaction = test_data::TransactionBuilder::with_output(1).add_input(&genesis.transactions[0], 0).into();
|
||||
let transaction_hash = transaction.hash();
|
||||
|
||||
// simulate transaction verification fail
|
||||
let mut verifier = DummyVerifier::default();
|
||||
verifier.error_when_verifying(transaction_hash.clone(), "simulated");
|
||||
|
||||
let (_, _, executor, _, local_node) = create_local_node(Some(verifier));
|
||||
|
||||
let _peer_index1 = local_node.create_sync_session(0, DummyOutboundSyncConnection::new());
|
||||
{ executor.lock().take_tasks(); }
|
||||
|
||||
let result = local_node.accept_transaction(transaction);
|
||||
assert_eq!(result, Err("simulated".to_owned()));
|
||||
|
||||
assert_eq!(executor.lock().take_tasks(), vec![]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ use synchronization_server::ServerTaskIndex;
|
|||
use synchronization_manager::{manage_synchronization_peers_blocks, manage_synchronization_peers_inventory,
|
||||
manage_unknown_orphaned_blocks, manage_orphaned_transactions, MANAGEMENT_INTERVAL_MS,
|
||||
ManagePeersConfig, ManageUnknownBlocksConfig, ManageOrphanTransactionsConfig};
|
||||
use synchronization_verifier::{Verifier, VerificationSink, VerificationTask};
|
||||
use synchronization_verifier::{Verifier, VerificationSink, BlockVerificationSink, TransactionVerificationSink, VerificationTask};
|
||||
use compact_block_builder::build_compact_block;
|
||||
use hash_queue::HashPosition;
|
||||
use miner::transaction_fee_rate;
|
||||
|
@ -164,6 +164,9 @@ const SYNC_SPEED_BLOCKS_TO_INSPECT: usize = 512;
|
|||
/// Number of blocks to inspect when calculating average blocks speed
|
||||
const BLOCKS_SPEED_BLOCKS_TO_INSPECT: usize = 512;
|
||||
|
||||
// No-error, no-result future
|
||||
type EmptyBoxFuture = BoxFuture<(), ()>;
|
||||
|
||||
/// Synchronization state
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum State {
|
||||
|
@ -210,11 +213,12 @@ pub trait Client : Send + 'static {
|
|||
fn on_peer_block_announcement_type(&mut self, peer_index: usize, announcement_type: BlockAnnouncementType);
|
||||
fn on_peer_feefilter(&mut self, peer_index: usize, message: &types::FeeFilter);
|
||||
fn on_peer_disconnected(&mut self, peer_index: usize);
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: BoxFuture<(), ()>);
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: EmptyBoxFuture);
|
||||
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<(), String>;
|
||||
}
|
||||
|
||||
/// Synchronization client trait
|
||||
pub trait ClientCore : VerificationSink {
|
||||
pub trait ClientCore {
|
||||
fn best_block(&self) -> db::BestBlock;
|
||||
fn state(&self) -> State;
|
||||
fn is_compact_block_sent_recently(&mut self, peer_index: usize, hash: &H256) -> bool;
|
||||
|
@ -232,9 +236,14 @@ pub trait ClientCore : VerificationSink {
|
|||
fn on_peer_block_announcement_type(&mut self, peer_index: usize, announcement_type: BlockAnnouncementType);
|
||||
fn on_peer_feefilter(&mut self, peer_index: usize, message: &types::FeeFilter);
|
||||
fn on_peer_disconnected(&mut self, peer_index: usize);
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: BoxFuture<(), ()>);
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: EmptyBoxFuture);
|
||||
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<VecDeque<(H256, Transaction)>, String>;
|
||||
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>);
|
||||
fn try_switch_to_saturated_state(&mut self) -> bool;
|
||||
fn on_block_verification_success(&mut self, block: IndexedBlock) -> Option<Vec<VerificationTask>>;
|
||||
fn on_block_verification_error(&mut self, err: &str, hash: &H256);
|
||||
fn on_transaction_verification_success(&mut self, transaction: Transaction);
|
||||
fn on_transaction_verification_error(&mut self, err: &str, hash: &H256);
|
||||
}
|
||||
|
||||
|
||||
|
@ -286,7 +295,7 @@ pub struct SynchronizationClientCore<T: TaskExecutor> {
|
|||
/// Cpu pool.
|
||||
pool: CpuPool,
|
||||
/// Sync management worker.
|
||||
management_worker: Option<BoxFuture<(), ()>>,
|
||||
management_worker: Option<EmptyBoxFuture>,
|
||||
/// Synchronization peers.
|
||||
peers: Peers,
|
||||
/// Task executor.
|
||||
|
@ -304,7 +313,9 @@ pub struct SynchronizationClientCore<T: TaskExecutor> {
|
|||
/// Verifying blocks by peer
|
||||
verifying_blocks_by_peer: HashMap<H256, usize>,
|
||||
/// Verifying blocks futures
|
||||
verifying_blocks_futures: HashMap<usize, (HashSet<H256>, Vec<BoxFuture<(), ()>>)>,
|
||||
verifying_blocks_futures: HashMap<usize, (HashSet<H256>, Vec<EmptyBoxFuture>)>,
|
||||
/// Verifying transactions futures
|
||||
verifying_transactions_sinks: HashMap<H256, Box<TransactionVerificationSink>>,
|
||||
/// Hashes of items we do not want to relay after verification is completed
|
||||
do_not_relay: HashSet<H256>,
|
||||
/// Block processing speed meter
|
||||
|
@ -315,6 +326,12 @@ pub struct SynchronizationClientCore<T: TaskExecutor> {
|
|||
config: Config,
|
||||
}
|
||||
|
||||
/// Verification sink for synchronization client core
|
||||
pub struct CoreVerificationSink<T: TaskExecutor> {
|
||||
/// Client core reference
|
||||
core: Arc<Mutex<SynchronizationClientCore<T>>>,
|
||||
}
|
||||
|
||||
/// Block headers provider from `headers` message
|
||||
pub struct MessageBlockHeadersProvider<'a> {
|
||||
/// sync chain
|
||||
|
@ -339,6 +356,12 @@ struct AverageSpeedMeter {
|
|||
last_timestamp: Option<f64>,
|
||||
}
|
||||
|
||||
/// Transaction append error
|
||||
enum AppendTransactionError {
|
||||
Synchronizing,
|
||||
Orphan(HashSet<H256>),
|
||||
}
|
||||
|
||||
impl FilteredInventory {
|
||||
#[cfg(test)]
|
||||
pub fn with_unfiltered(unfiltered: Vec<InventoryVector>) -> Self {
|
||||
|
@ -479,9 +502,18 @@ impl<T, U> Client for SynchronizationClient<T, U> where T: TaskExecutor, U: Veri
|
|||
self.core.lock().on_peer_disconnected(peer_index);
|
||||
}
|
||||
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: BoxFuture<(), ()>) {
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: EmptyBoxFuture) {
|
||||
self.core.lock().after_peer_nearly_blocks_verified(peer_index, future);
|
||||
}
|
||||
|
||||
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<(), String> {
|
||||
let mut transactions_to_verify = try!(self.core.lock().accept_transaction(transaction, sink));
|
||||
let next_block_height = self.best_block().number + 1;
|
||||
while let Some((_, tx)) = transactions_to_verify.pop_front() {
|
||||
self.verifier.verify_transaction(next_block_height, tx);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> SynchronizationClient<T, U> where T: TaskExecutor, U: Verifier {
|
||||
|
@ -778,7 +810,7 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
|
||||
/// Execute after last block from this peer in NearlySaturated state is verified.
|
||||
/// If there are no verifying blocks from this peer or we are not in the NearlySaturated state => execute immediately.
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: BoxFuture<(), ()>) {
|
||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: usize, future: EmptyBoxFuture) {
|
||||
// if we are currently synchronizing => no need to wait
|
||||
if self.state.is_synchronizing() {
|
||||
future.wait().expect("no-error future");
|
||||
|
@ -794,6 +826,18 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<VecDeque<(H256, Transaction)>, String> {
|
||||
let hash = transaction.hash();
|
||||
match self.try_append_transaction(hash.clone(), transaction, true) {
|
||||
Err(AppendTransactionError::Orphan(_)) => Err("Cannot append transaction as its inputs are unknown".to_owned()),
|
||||
Err(AppendTransactionError::Synchronizing) => Err("Cannot append transaction as node is not yet fully synchronized".to_owned()),
|
||||
Ok(transactions) => {
|
||||
self.verifying_transactions_sinks.insert(hash, sink);
|
||||
Ok(transactions)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Schedule new synchronization tasks, if any.
|
||||
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>) {
|
||||
let mut tasks: Vec<Task> = Vec::new();
|
||||
|
@ -951,10 +995,7 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
|
||||
switch_to_saturated
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor {
|
||||
/// Process successful block verification
|
||||
fn on_block_verification_success(&mut self, block: IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
// update block processing speed
|
||||
self.block_speed_meter.checkpoint();
|
||||
|
@ -1018,7 +1059,6 @@ impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor
|
|||
}
|
||||
}
|
||||
|
||||
/// Process failed block verification
|
||||
fn on_block_verification_error(&mut self, err: &str, hash: &H256) {
|
||||
warn!(target: "sync", "Block {:?} verification failed with error {:?}", hash.to_reversed_str(), err);
|
||||
|
||||
|
@ -1050,7 +1090,6 @@ impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor
|
|||
self.execute_synchronization_tasks(None, None);
|
||||
}
|
||||
|
||||
/// Process successful transaction verification
|
||||
fn on_transaction_verification_success(&mut self, transaction: Transaction) {
|
||||
let hash = transaction.hash();
|
||||
let needs_relay = !self.do_not_relay.remove(&hash);
|
||||
|
@ -1074,11 +1113,15 @@ impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor
|
|||
|
||||
// relay transaction to peers
|
||||
if needs_relay {
|
||||
self.relay_new_transactions(vec![(hash, &transaction, transaction_fee_rate)]);
|
||||
self.relay_new_transactions(vec![(hash.clone(), &transaction, transaction_fee_rate)]);
|
||||
}
|
||||
|
||||
// call verification future, if any
|
||||
if let Some(mut future_sink) = self.verifying_transactions_sinks.remove(&hash) {
|
||||
(&mut future_sink).on_transaction_verification_success(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
/// Process failed transaction verification
|
||||
fn on_transaction_verification_error(&mut self, err: &str, hash: &H256) {
|
||||
warn!(target: "sync", "Transaction {:?} verification failed with error {:?}", hash.to_reversed_str(), err);
|
||||
|
||||
|
@ -1090,6 +1133,46 @@ impl<T> VerificationSink for SynchronizationClientCore<T> where T: TaskExecutor
|
|||
// forget for this transaction and all its children
|
||||
chain.forget_verifying_transaction_with_children(hash);
|
||||
}
|
||||
|
||||
// call verification future, if any
|
||||
if let Some(mut future_sink) = self.verifying_transactions_sinks.remove(hash) {
|
||||
(&mut future_sink).on_transaction_verification_error(err, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CoreVerificationSink<T> where T: TaskExecutor {
|
||||
pub fn new(core: Arc<Mutex<SynchronizationClientCore<T>>>) -> Self {
|
||||
CoreVerificationSink {
|
||||
core: core,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> VerificationSink for CoreVerificationSink<T> where T: TaskExecutor {
|
||||
}
|
||||
|
||||
impl<T> BlockVerificationSink for CoreVerificationSink<T> where T: TaskExecutor {
|
||||
/// Process successful block verification
|
||||
fn on_block_verification_success(&self, block: IndexedBlock) -> Option<Vec<VerificationTask>> {
|
||||
self.core.lock().on_block_verification_success(block)
|
||||
}
|
||||
|
||||
/// Process failed block verification
|
||||
fn on_block_verification_error(&self, err: &str, hash: &H256) {
|
||||
self.core.lock().on_block_verification_error(err, hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TransactionVerificationSink for CoreVerificationSink<T> where T: TaskExecutor {
|
||||
/// Process successful transaction verification
|
||||
fn on_transaction_verification_success(&self, transaction: Transaction) {
|
||||
self.core.lock().on_transaction_verification_success(transaction)
|
||||
}
|
||||
|
||||
/// Process failed transaction verification
|
||||
fn on_transaction_verification_error(&self, err: &str, hash: &H256) {
|
||||
self.core.lock().on_transaction_verification_error(err, hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1110,6 +1193,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
verify_headers: true,
|
||||
verifying_blocks_by_peer: HashMap::new(),
|
||||
verifying_blocks_futures: HashMap::new(),
|
||||
verifying_transactions_sinks: HashMap::new(),
|
||||
do_not_relay: HashSet::new(),
|
||||
block_speed_meter: AverageSpeedMeter::with_inspect_items(SYNC_SPEED_BLOCKS_TO_INSPECT),
|
||||
sync_speed_meter: AverageSpeedMeter::with_inspect_items(BLOCKS_SPEED_BLOCKS_TO_INSPECT),
|
||||
|
@ -1458,9 +1542,20 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
|
||||
/// Process new peer transaction
|
||||
fn process_peer_transaction(&mut self, _peer_index: Option<usize>, hash: H256, transaction: Transaction, relay: bool) -> Option<VecDeque<(H256, Transaction)>> {
|
||||
match self.try_append_transaction(hash.clone(), transaction.clone(), relay) {
|
||||
Err(AppendTransactionError::Orphan(unknown_parents)) => {
|
||||
self.orphaned_transactions_pool.insert(hash, transaction, unknown_parents);
|
||||
None
|
||||
},
|
||||
Err(AppendTransactionError::Synchronizing) => None,
|
||||
Ok(transactions) => Some(transactions),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_append_transaction(&mut self, hash: H256, transaction: Transaction, relay: bool) -> Result<VecDeque<(H256, Transaction)>, AppendTransactionError> {
|
||||
// if we are in synchronization state, we will ignore this message
|
||||
if self.state.is_synchronizing() {
|
||||
return None;
|
||||
return Err(AppendTransactionError::Synchronizing);
|
||||
}
|
||||
|
||||
// else => verify transaction + it's orphans and then add to the memory pool
|
||||
|
@ -1472,8 +1567,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
.map(|input| input.previous_output.hash.clone())
|
||||
.collect();
|
||||
if !unknown_parents.is_empty() {
|
||||
self.orphaned_transactions_pool.insert(hash, transaction, unknown_parents);
|
||||
return None;
|
||||
return Err(AppendTransactionError::Orphan(unknown_parents));
|
||||
}
|
||||
|
||||
// else verify && insert this transaction && all dependent orphans
|
||||
|
@ -1487,7 +1581,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
self.do_not_relay.insert(h.clone());
|
||||
}
|
||||
}
|
||||
Some(transactions)
|
||||
Ok(transactions)
|
||||
}
|
||||
|
||||
fn forget_failed_blocks(&mut self, blocks_to_forget: &[H256]) {
|
||||
|
@ -1563,7 +1657,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Awake threads, waiting for this block
|
||||
/// Execute futures, which were waiting for this block verification
|
||||
fn awake_waiting_threads(&mut self, hash: &H256) {
|
||||
// find a peer, which has supplied us with this block
|
||||
if let Entry::Occupied(block_entry) = self.verifying_blocks_by_peer.entry(hash.clone()) {
|
||||
|
@ -1698,7 +1792,8 @@ pub mod tests {
|
|||
use network::Magic;
|
||||
use message::common::{InventoryVector, InventoryType};
|
||||
use message::types;
|
||||
use super::{Client, Config, SynchronizationClient, SynchronizationClientCore, BlockAnnouncementType, MessageBlockHeadersProvider};
|
||||
use super::{Client, Config, SynchronizationClient, SynchronizationClientCore, CoreVerificationSink,
|
||||
BlockAnnouncementType, MessageBlockHeadersProvider};
|
||||
use connection_filter::tests::*;
|
||||
use synchronization_executor::Task;
|
||||
use synchronization_chain::{Chain, ChainRef};
|
||||
|
@ -1735,7 +1830,7 @@ pub mod tests {
|
|||
client_core.lock().verify_headers(false);
|
||||
}
|
||||
let mut verifier = verifier.unwrap_or_default();
|
||||
verifier.set_sink(client_core.clone());
|
||||
verifier.set_sink(Arc::new(CoreVerificationSink::new(client_core.clone())));
|
||||
let client = SynchronizationClient::new(client_core.clone(), verifier);
|
||||
(event_loop, handle, executor, chain, client_core, client)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::thread;
|
|||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use parking_lot::Mutex;
|
||||
use chain::{Transaction, OutPoint, TransactionOutput};
|
||||
use network::Magic;
|
||||
use primitives::hash::H256;
|
||||
|
@ -11,16 +10,24 @@ use verification::{ChainVerifier, Verify as VerificationVerify, Chain};
|
|||
use db::{SharedStore, IndexedBlock, PreviousTransactionOutputProvider};
|
||||
use time::get_time;
|
||||
|
||||
/// Verification events sink
|
||||
pub trait VerificationSink : Send + 'static {
|
||||
/// Block verification events sink
|
||||
pub trait BlockVerificationSink : Send + Sync + 'static {
|
||||
/// When block verification has completed successfully.
|
||||
fn on_block_verification_success(&mut self, block: IndexedBlock) -> Option<Vec<VerificationTask>>;
|
||||
fn on_block_verification_success(&self, block: IndexedBlock) -> Option<Vec<VerificationTask>>;
|
||||
/// When block verification has failed.
|
||||
fn on_block_verification_error(&mut self, err: &str, hash: &H256);
|
||||
fn on_block_verification_error(&self, err: &str, hash: &H256);
|
||||
}
|
||||
|
||||
/// Transaction verification events sink
|
||||
pub trait TransactionVerificationSink : Send + Sync + 'static {
|
||||
/// When transaction verification has completed successfully.
|
||||
fn on_transaction_verification_success(&mut self, transaction: Transaction);
|
||||
fn on_transaction_verification_success(&self, transaction: Transaction);
|
||||
/// When transaction verification has failed.
|
||||
fn on_transaction_verification_error(&mut self, err: &str, hash: &H256);
|
||||
fn on_transaction_verification_error(&self, err: &str, hash: &H256);
|
||||
}
|
||||
|
||||
/// Verification events sink
|
||||
pub trait VerificationSink : BlockVerificationSink + TransactionVerificationSink {
|
||||
}
|
||||
|
||||
/// Verification thread tasks
|
||||
|
@ -60,7 +67,7 @@ struct EmptyTransactionOutputProvider {
|
|||
|
||||
impl AsyncVerifier {
|
||||
/// Create new async verifier
|
||||
pub fn new<T: VerificationSink>(verifier: Arc<ChainVerifier>, chain: ChainRef, sink: Arc<Mutex<T>>) -> Self {
|
||||
pub fn new<T: VerificationSink>(verifier: Arc<ChainVerifier>, chain: ChainRef, sink: Arc<T>) -> Self {
|
||||
let (verification_work_sender, verification_work_receiver) = channel();
|
||||
AsyncVerifier {
|
||||
verification_work_sender: verification_work_sender,
|
||||
|
@ -74,7 +81,7 @@ impl AsyncVerifier {
|
|||
}
|
||||
|
||||
/// Thread procedure for handling verification tasks
|
||||
fn verification_worker_proc<T: VerificationSink>(sink: Arc<Mutex<T>>, chain: ChainRef, verifier: Arc<ChainVerifier>, work_receiver: Receiver<VerificationTask>) {
|
||||
fn verification_worker_proc<T: VerificationSink>(sink: Arc<T>, chain: ChainRef, verifier: Arc<ChainVerifier>, work_receiver: Receiver<VerificationTask>) {
|
||||
while let Ok(task) = work_receiver.recv() {
|
||||
match task {
|
||||
VerificationTask::Stop => break,
|
||||
|
@ -119,12 +126,12 @@ pub struct SyncVerifier<T: VerificationSink> {
|
|||
/// Verifier
|
||||
verifier: ChainVerifier,
|
||||
/// Verification sink
|
||||
sink: Arc<Mutex<T>>,
|
||||
sink: Arc<T>,
|
||||
}
|
||||
|
||||
impl<T> SyncVerifier<T> where T: VerificationSink {
|
||||
/// Create new sync verifier
|
||||
pub fn new(network: Magic, storage: SharedStore, sink: Arc<Mutex<T>>) -> Self {
|
||||
pub fn new(network: Magic, storage: SharedStore, sink: Arc<T>) -> Self {
|
||||
let verifier = ChainVerifier::new(storage, network);
|
||||
SyncVerifier {
|
||||
verifier: verifier,
|
||||
|
@ -146,7 +153,7 @@ impl<T> Verifier for SyncVerifier<T> where T: VerificationSink {
|
|||
}
|
||||
|
||||
/// Execute single verification task
|
||||
fn execute_verification_task<T: VerificationSink, U: PreviousTransactionOutputProvider>(sink: &Arc<Mutex<T>>, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) {
|
||||
fn execute_verification_task<T: VerificationSink, U: PreviousTransactionOutputProvider>(sink: &Arc<T>, tx_output_provider: &U, verifier: &ChainVerifier, task: VerificationTask) {
|
||||
let mut tasks_queue: VecDeque<VerificationTask> = VecDeque::new();
|
||||
tasks_queue.push_back(task);
|
||||
|
||||
|
@ -156,24 +163,24 @@ fn execute_verification_task<T: VerificationSink, U: PreviousTransactionOutputPr
|
|||
// verify block
|
||||
match verifier.verify(&block) {
|
||||
Ok(Chain::Main) | Ok(Chain::Side) => {
|
||||
if let Some(tasks) = sink.lock().on_block_verification_success(block) {
|
||||
if let Some(tasks) = sink.on_block_verification_success(block) {
|
||||
tasks_queue.extend(tasks);
|
||||
}
|
||||
},
|
||||
Ok(Chain::Orphan) => {
|
||||
// this can happen for B1 if B0 verification has failed && we have already scheduled verification of B0
|
||||
sink.lock().on_block_verification_error(&format!("orphaned block because parent block verification has failed"), &block.hash())
|
||||
sink.on_block_verification_error(&format!("orphaned block because parent block verification has failed"), &block.hash())
|
||||
},
|
||||
Err(e) => {
|
||||
sink.lock().on_block_verification_error(&format!("{:?}", e), &block.hash())
|
||||
sink.on_block_verification_error(&format!("{:?}", e), &block.hash())
|
||||
}
|
||||
}
|
||||
},
|
||||
VerificationTask::VerifyTransaction(height, transaction) => {
|
||||
let time: u32 = get_time().sec as u32;
|
||||
match verifier.verify_transaction(tx_output_provider, height, time, &transaction, 1) {
|
||||
Ok(_) => sink.lock().on_transaction_verification_success(transaction),
|
||||
Err(e) => sink.lock().on_transaction_verification_error(&format!("{:?}", e), &transaction.hash()),
|
||||
Ok(_) => sink.on_transaction_verification_success(transaction),
|
||||
Err(e) => sink.on_transaction_verification_error(&format!("{:?}", e), &transaction.hash()),
|
||||
}
|
||||
},
|
||||
_ => unreachable!("must be checked by caller"),
|
||||
|
@ -213,22 +220,21 @@ impl PreviousTransactionOutputProvider for EmptyTransactionOutputProvider {
|
|||
pub mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use chain::Transaction;
|
||||
use synchronization_client::SynchronizationClientCore;
|
||||
use synchronization_client::CoreVerificationSink;
|
||||
use synchronization_executor::tests::DummyTaskExecutor;
|
||||
use primitives::hash::H256;
|
||||
use super::{Verifier, VerificationSink};
|
||||
use super::{Verifier, BlockVerificationSink, TransactionVerificationSink};
|
||||
use db::IndexedBlock;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DummyVerifier {
|
||||
sink: Option<Arc<Mutex<SynchronizationClientCore<DummyTaskExecutor>>>>,
|
||||
sink: Option<Arc<CoreVerificationSink<DummyTaskExecutor>>>,
|
||||
errors: HashMap<H256, String>
|
||||
}
|
||||
|
||||
impl DummyVerifier {
|
||||
pub fn set_sink(&mut self, sink: Arc<Mutex<SynchronizationClientCore<DummyTaskExecutor>>>) {
|
||||
pub fn set_sink(&mut self, sink: Arc<CoreVerificationSink<DummyTaskExecutor>>) {
|
||||
self.sink = Some(sink);
|
||||
}
|
||||
|
||||
|
@ -241,9 +247,9 @@ pub mod tests {
|
|||
fn verify_block(&self, block: IndexedBlock) {
|
||||
match self.sink {
|
||||
Some(ref sink) => match self.errors.get(&block.hash()) {
|
||||
Some(err) => sink.lock().on_block_verification_error(&err, &block.hash()),
|
||||
Some(err) => sink.on_block_verification_error(&err, &block.hash()),
|
||||
None => {
|
||||
sink.lock().on_block_verification_success(block);
|
||||
sink.on_block_verification_success(block);
|
||||
()
|
||||
},
|
||||
},
|
||||
|
@ -254,8 +260,8 @@ pub mod tests {
|
|||
fn verify_transaction(&self, _height: u32, transaction: Transaction) {
|
||||
match self.sink {
|
||||
Some(ref sink) => match self.errors.get(&transaction.hash()) {
|
||||
Some(err) => sink.lock().on_transaction_verification_error(&err, &transaction.hash()),
|
||||
None => sink.lock().on_transaction_verification_success(transaction),
|
||||
Some(err) => sink.on_transaction_verification_error(&err, &transaction.hash()),
|
||||
None => sink.on_transaction_verification_success(transaction),
|
||||
},
|
||||
None => panic!("call set_sink"),
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ cargo clippy -p miner
|
|||
cargo clippy -p network
|
||||
cargo clippy -p p2p
|
||||
cargo clippy -p primitives
|
||||
cargo clippy -p rpc
|
||||
cargo clippy -p script
|
||||
cargo clippy -p serialization
|
||||
cargo clippy -p sync
|
||||
|
|
|
@ -13,6 +13,7 @@ cargo test\
|
|||
-p pbtc\
|
||||
-p p2p\
|
||||
-p primitives\
|
||||
-p rpc\
|
||||
-p script\
|
||||
-p serialization\
|
||||
-p sync\
|
||||
|
|
Loading…
Reference in New Issue