From 44499550d9ed7375fe6b93b63918da833b1bdd90 Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Tue, 30 Jan 2018 18:49:52 +0100 Subject: [PATCH] Networking and in-memory client (#38) * Networking crate draft * Started work on syncing algo * Fixed query range * BlockCollection tests * In-mem client backend * Fixed tests * Renamed Transaction * Removed stray println * Docs --- substrate/Cargo.lock | 515 ++++++++++++++++-- substrate/Cargo.toml | 2 + substrate/cli/src/error.rs | 5 + substrate/cli/src/lib.rs | 19 +- substrate/client/Cargo.toml | 3 + substrate/client/src/backend.rs | 53 ++ substrate/client/src/blockchain.rs | 86 +++ substrate/client/src/error.rs | 24 +- substrate/client/src/in_mem.rs | 204 +++++++ substrate/client/src/lib.rs | 165 ++++-- substrate/network/Cargo.toml | 29 + substrate/network/src/blocks.rs | 263 +++++++++ substrate/network/src/chain.rs | 59 ++ substrate/network/src/config.rs | 30 + .../test_helpers.rs => network/src/error.rs} | 34 +- substrate/network/src/io.rs | 78 +++ substrate/network/src/lib.rs | 62 +++ substrate/network/src/message.rs | 189 +++++++ substrate/network/src/protocol.rs | 347 ++++++++++++ substrate/network/src/service.rs | 239 ++++++++ substrate/network/src/sync.rs | 372 +++++++++++++ substrate/network/src/test/mod.rs | 0 substrate/primitives/src/block.rs | 14 +- substrate/primitives/src/parachain.rs | 2 +- substrate/rpc/src/chain/mod.rs | 10 +- substrate/rpc/src/chain/tests.rs | 13 +- substrate/rpc/src/lib.rs | 3 - substrate/rpc/src/state/mod.rs | 3 +- substrate/rpc/src/state/tests.rs | 12 +- substrate/state_machine/src/backend.rs | 4 +- substrate/state_machine/src/lib.rs | 4 +- 31 files changed, 2689 insertions(+), 154 deletions(-) create mode 100644 substrate/client/src/backend.rs create mode 100644 substrate/client/src/blockchain.rs create mode 100644 substrate/client/src/in_mem.rs create mode 100644 substrate/network/Cargo.toml create mode 100644 substrate/network/src/blocks.rs create mode 100644 substrate/network/src/chain.rs create mode 100644 substrate/network/src/config.rs rename substrate/{rpc/src/test_helpers.rs => network/src/error.rs} (54%) create mode 100644 substrate/network/src/io.rs create mode 100644 substrate/network/src/lib.rs create mode 100644 substrate/network/src/message.rs create mode 100644 substrate/network/src/protocol.rs create mode 100644 substrate/network/src/service.rs create mode 100644 substrate/network/src/sync.rs create mode 100644 substrate/network/src/test/mod.rs diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index c741c845a5..e06448d06d 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -46,7 +46,7 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -98,6 +98,11 @@ name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -160,6 +165,11 @@ name = "constant_time_eq" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crossbeam" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crunchy" version = "0.1.6" @@ -184,6 +194,11 @@ name = "dtoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "edit-distance" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "either" version = "1.4.0" @@ -215,7 +230,31 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "eth-secp256k1" +version = "0.5.6" +source = "git+https://github.com/paritytech/rust-secp256k1#b6b67055edc929057e97d64f036c78ad91f58a7f" +dependencies = [ + "arrayvec 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethcore-bigint" +version = "0.2.1" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "plain_hasher 0.1.0 (git+https://github.com/paritytech/parity.git)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -231,11 +270,44 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-bytes" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" + [[package]] name = "ethcore-bytes" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ethcore-io" +version = "1.9.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethcore-logger" +version = "1.9.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "isatty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-logger" version = "1.9.0" @@ -245,13 +317,77 @@ dependencies = [ "arrayvec 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-network" +version = "1.9.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)", + "ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-io 1.9.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-logger 1.9.0 (git+https://github.com/paritytech/parity.git)", + "ethcrypto 0.1.0 (git+https://github.com/paritytech/parity.git)", + "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", + "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", + "keccak-hash 0.1.0 (git+https://github.com/paritytech/parity.git)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "path 0.1.0 (git+https://github.com/paritytech/parity.git)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp 0.2.1 (git+https://github.com/paritytech/parity.git)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethcrypto" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)", + "ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)", + "ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethkey" +version = "0.3.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)", + "ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixed-hash" version = "0.1.0" @@ -301,6 +437,9 @@ dependencies = [ name = "gcc" version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "globset" @@ -338,7 +477,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.11.6" +version = "0.10.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.3 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -356,7 +513,29 @@ dependencies = [ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "igd" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,6 +547,11 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ipnetwork" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "isatty" version = "0.1.5" @@ -378,6 +562,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.3.4" @@ -386,42 +578,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#8f921ed65cda3fba0ce55d31ed62c7f0c3b32966" +source = "git+https://github.com/paritytech/jsonrpc.git#0eba7e745b0895b4234cd8d89b28e10e2c3c34a4" dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-http-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#8f921ed65cda3fba0ce55d31ed62c7f0c3b32966" +source = "git+https://github.com/paritytech/jsonrpc.git#0eba7e745b0895b4234cd8d89b28e10e2c3c34a4" dependencies = [ - "hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", "jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-macros" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#8f921ed65cda3fba0ce55d31ed62c7f0c3b32966" +source = "git+https://github.com/paritytech/jsonrpc.git#0eba7e745b0895b4234cd8d89b28e10e2c3c34a4" dependencies = [ "jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", "jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "jsonrpc-pubsub" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#8f921ed65cda3fba0ce55d31ed62c7f0c3b32966" +source = "git+https://github.com/paritytech/jsonrpc.git#0eba7e745b0895b4234cd8d89b28e10e2c3c34a4" dependencies = [ "jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -431,7 +623,7 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#8f921ed65cda3fba0ce55d31ed62c7f0c3b32966" +source = "git+https://github.com/paritytech/jsonrpc.git#0eba7e745b0895b4234cd8d89b28e10e2c3c34a4" dependencies = [ "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -441,6 +633,16 @@ dependencies = [ "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "keccak-hash" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)", + "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "keccak-hash" version = "0.1.0" @@ -467,7 +669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -490,6 +692,11 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "matches" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memchr" version = "1.0.2" @@ -512,12 +719,20 @@ dependencies = [ "rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mime" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -610,6 +825,16 @@ dependencies = [ "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parity-wordlist" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot" version = "0.4.8" @@ -640,6 +865,11 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "path" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" + [[package]] name = "patricia-trie" version = "0.1.0" @@ -663,6 +893,14 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plain_hasher" +version = "0.1.0" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "plain_hasher" version = "0.1.0" @@ -677,6 +915,7 @@ version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-cli 0.1.0", + "polkadot-network 0.1.0", ] [[package]] @@ -707,7 +946,10 @@ name = "polkadot-client" version = "0.1.0" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-primitives 0.1.0", + "polkadot-serializer 0.1.0", "polkadot-state-machine 0.1.0", ] @@ -734,8 +976,33 @@ dependencies = [ "polkadot-state-machine 0.1.0", "runtime-std 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "polkadot-network" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-io 1.9.0 (git+https://github.com/paritytech/parity.git)", + "ethcore-network 1.9.0 (git+https://github.com/paritytech/parity.git)", + "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-client 0.1.0", + "polkadot-primitives 0.1.0", + "polkadot-serializer 0.1.0", + "polkadot-state-machine 0.1.0", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -750,8 +1017,8 @@ dependencies = [ "pretty_assertions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "uint 0.1.0 (git+https://github.com/paritytech/primitives.git)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -784,7 +1051,7 @@ dependencies = [ name = "polkadot-serializer" version = "0.1.0" dependencies = [ - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -807,7 +1074,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "polkadot-primitives 0.1.0", "polkadot-serializer 0.1.0", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -847,7 +1114,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -897,12 +1164,24 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp" +version = "0.2.1" +source = "git+https://github.com/paritytech/parity.git#dde6baedeca4b2dccaf2eacfbd2453b3d191596e" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rlp" version = "0.2.1" @@ -911,7 +1190,7 @@ dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -926,6 +1205,18 @@ dependencies = [ "polkadot-state-machine 0.1.0", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-demangle" version = "0.1.5" @@ -937,12 +1228,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc_version" -version = "0.1.7" +name = "rustc-serialize" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rustc_version" @@ -967,11 +1255,6 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "semver" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "semver" version = "0.6.0" @@ -987,12 +1270,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1017,9 +1300,14 @@ dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "slab" version = "0.3.0" @@ -1039,6 +1327,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "smallvec" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "snappy" +version = "0.1.0" +source = "git+https://github.com/paritytech/rust-snappy#858eac97192ea25d18d3f3626a8cc13ca0b175bb" +dependencies = [ + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)", +] + +[[package]] +name = "snappy-sys" +version = "0.1.0" +source = "git+https://github.com/paritytech/rust-snappy#858eac97192ea25d18d3f3626a8cc13ca0b175bb" +dependencies = [ + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "stable_deref_trait" @@ -1050,6 +1359,14 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "subtle" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "0.11.11" @@ -1096,7 +1413,7 @@ name = "thread_local" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1175,6 +1492,11 @@ dependencies = [ "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "triehash" version = "0.1.0" @@ -1193,6 +1515,11 @@ dependencies = [ "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "uint" version = "0.1.0" @@ -1205,12 +1532,33 @@ dependencies = [ [[package]] name = "unicase" -version = "2.0.0" +version = "1.4.2" 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)", + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicase" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-width" version = "0.1.4" @@ -1234,6 +1582,16 @@ name = "untrusted" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "url" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1244,6 +1602,11 @@ name = "vec_map" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "void" version = "1.0.2" @@ -1268,6 +1631,22 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xml-rs" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmltree" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "yaml-rust" version = "0.3.5" @@ -1280,12 +1659,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum assert_matches 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e772942dccdf11b368c31e044e4fca9189f80a773d2f0808379de65894cbf57" "checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860" -"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" +"checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bigint 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5442186ef6560f30f1ee4b9c1e4c87a35a6879d3644550cc248ec2b955eb5fcd" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" +"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" @@ -1294,17 +1674,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" +"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a34f5204fbc13582de418611cf3a7dcdd07c6d312a5b631597ba72c06b9d9c9" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum eth-secp256k1 0.5.6 (git+https://github.com/paritytech/rust-secp256k1)" = "" +"checksum ethcore-bigint 0.2.1 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb5af77e74a8f70e9c3337e069c37bc82178ef1b459c02091f73c4ad5281eb5" +"checksum ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3977c772cd6c5c22e1c7cfa208e4c3b746bd6c3a6c8eeec0999a6b2103015ad5" +"checksum ethcore-io 1.9.0 (git+https://github.com/paritytech/parity.git)" = "" +"checksum ethcore-logger 1.9.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum ethcore-logger 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fd5813e49546030be7d134e775088d56b8ff4ab60617b90e93d4f0513da4c5b" +"checksum ethcore-network 1.9.0 (git+https://github.com/paritytech/parity.git)" = "" +"checksum ethcrypto 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" +"checksum ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum fixed-hash 0.1.0 (git+https://github.com/paritytech/primitives.git)" = "" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" @@ -1316,25 +1706,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum hashdb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d97be07c358c5b461268b4ce60304024c5fa5acfd4bd8cd743639f0252003cf5" "checksum heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "54fab2624374e5137ae4df13bf32b0b269cb804df42d13a51221bbd431d1a237" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.11.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b45eac8b696d59491b079bd04fcb0f3488c0f6ed62dcb36bcfea8a543e9cdc3" +"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" +"checksum hyper 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4959ca95f55df4265bff2ad63066147255e6fa733682cf6d1cb5eaff6e53324b" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356a0dc23a4fa0f8ce4777258085d00a01ea4923b2efd93538fc44bf5e1bda76" "checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" +"checksum ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2134e210e2a024b5684f90e1556d5f71a1ce7f8b12e9ac9924c67fb36f63b336" "checksum isatty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "00c9301a947a2eaee7ce2556b80285dcc89558d07088962e6e8b9c25730f9dc6" +"checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" "checksum jsonrpc-http-server 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" "checksum jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" "checksum jsonrpc-pubsub 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" "checksum jsonrpc-server-utils 8.0.0 (git+https://github.com/paritytech/jsonrpc.git)" = "" +"checksum keccak-hash 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f300c1f149cd9ca5214eed24f6e713a597517420fb8b15499824aa916259ec1" "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.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" +"checksum lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "236eb37a62591d4a41a89b7763d7de3e06ca02d5ab2815446a8bae5d2f8c2d57" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" "checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memorydb 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "013b7e4c5e10c764936ebc6bd3662d8e3c92292d267bf6a42ef3f5cad9c793ee" +"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" "checksum mio 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0e8411968194c7b139e9105bc4ae7db0bae232af087147e72f0616ebf5fdb9cb" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" @@ -1345,11 +1743,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parity-wasm 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "235801e9531998c4bb307f4ea6833c9f40a4cf132895219ac8c2cd25a9b310f7" +"checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e7f7c9857874e54afeb950eebeae662b1e51a2493666d2ea4c0a5d91dcf0412" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" +"checksum path 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum patricia-trie 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2f638d79aba5c4a71a4f373df6e3cd702250a53b7f0ed4da1e2a7be9737ae" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum plain_hasher 0.1.0 (git+https://github.com/paritytech/parity.git)" = "" "checksum plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83ae80873992f511142c07d0ec6c44de5636628fdb7e204abd655932ea79d995" "checksum pretty_assertions 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94b6bbc8a323d89a019c4cdde21850522fb8405e97add70827177fc2f86c1495" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" @@ -1362,27 +1763,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" "checksum ring 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f7d28b30a72c01b458428e0ae988d4149c20d902346902be881e3edc4bb325c" +"checksum rlp 0.2.1 (git+https://github.com/paritytech/parity.git)" = "" "checksum rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "babe6fce20c0ca9b1582998734c4569082d0ad08e43772a1c6c40aef4f106ef9" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" -"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "0c9cab69e16835717c9b8bd13c29f92b6aa34fe32ce2866b1ab481cf2da8442a" -"checksum serde_derive 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "3bdafe3e71710131a919735916caa5b18c2754ad0d33d8ae5d586ccc804a403e" +"checksum serde 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a2b181dd2b4a6353e828e44807269a761d3ecbc388a1f5ed3998ea69a516d9c" +"checksum serde_derive 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "31ce3c16ec18abb97d977f75880986549213b0c18f2695eda8b31eadc96eda4a" "checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab" "checksum serde_json 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e4586746d1974a030c48919731ecffd0ed28d0c40749d0d18d43b3a7d6c9b20e" +"checksum slab 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6dbdd334bd28d328dad1c41b0ea662517883d8880d8533895ef96c8003dec9c4" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" "checksum smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4f357e8cd37bf8822e1b964e96fd39e2cb5a0424f8aaa284ccaccc2162411c" +"checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" +"checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" +"checksum subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b811576c12506ff3f6da145585dc833edc32ee34c9fc021127d90e8134cc05c" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" @@ -1396,18 +1802,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9291c7f0fae44858b5e087dd462afb382354120003778f1695b44aab98c7abd7" "checksum twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "475352206e7a290c5fccc27624a163e8d0d115f7bb60ca18a64fc9ce056d7435" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum uint 0.1.0 (git+https://github.com/paritytech/primitives.git)" = "" -"checksum unicase 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e01da42520092d0cd2d6ac3ae69eb21a22ad43ff195676b86f8c37f487d6b80" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" +"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "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" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" +"checksum xmltree 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "472a9d37c7c53ab2391161df5b89b1f3bf76dab6ab150d7941ecbdd832282082" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 21232d39ef..99a0774da5 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Parity Technologies "] [dependencies] error-chain = "0.11" polkadot-cli = { path = "cli", version = "0.1" } +polkadot-network = { path = "network" } [workspace] members = [ @@ -21,6 +22,7 @@ members = [ "serializer", "state_machine", "validator", + "network", ] exclude = [ "wasm-runtime" diff --git a/substrate/cli/src/error.rs b/substrate/cli/src/error.rs index c4e8cbcc5e..6b1e2b6024 100644 --- a/substrate/cli/src/error.rs +++ b/substrate/cli/src/error.rs @@ -16,9 +16,14 @@ //! Initialization errors. +use client; + error_chain! { foreign_links { Io(::std::io::Error) #[doc="IO error"]; Cli(::clap::Error) #[doc="CLI error"]; } + links { + Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"]; + } } diff --git a/substrate/cli/src/lib.rs b/substrate/cli/src/lib.rs index 73168b73b4..d396a7c69e 100644 --- a/substrate/cli/src/lib.rs +++ b/substrate/cli/src/lib.rs @@ -48,14 +48,13 @@ pub fn run(args: I) -> error::Result<()> where let yaml = load_yaml!("./cli.yml"); let matches = clap::App::from_yaml(yaml).version(crate_version!()).get_matches_from_safe(args)?; - // TODO [ToDr] Split paremeters parsing from actual execution. + // TODO [ToDr] Split parameters parsing from actual execution. let log_pattern = matches.value_of("log").unwrap_or(""); init_logger(log_pattern); // Create client - let blockchain = DummyBlockchain; let executor = executor::executor(); - let client = client::Client::new(blockchain, executor); + let client = client::new_in_mem(executor)?; let address = "127.0.0.1:9933".parse().unwrap(); let handler = rpc::rpc_handler(client); @@ -96,17 +95,3 @@ fn init_logger(pattern: &str) { builder.init().expect("Logger initialized only once."); } -#[derive(Debug, Default)] -struct DummyBlockchain; - -impl client::Blockchain for DummyBlockchain { - type Error = (); - - fn latest_hash(&self) -> Result { - Ok(0.into()) - } - - fn header(&self, _hash: &primitives::block::HeaderHash) -> Result, Self::Error> { - Ok(None) - } -} diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 2142732b5d..468cf42de1 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -5,5 +5,8 @@ authors = ["Parity Technologies "] [dependencies] error-chain = "0.11" +log = "0.3" +parking_lot = "0.4" polkadot-primitives = { path = "../primitives", version = "0.1" } polkadot-state-machine = { path = "../state_machine", version = "0.1" } +polkadot-serializer = { path = "../serializer" } diff --git a/substrate/client/src/backend.rs b/substrate/client/src/backend.rs new file mode 100644 index 0000000000..76422528e7 --- /dev/null +++ b/substrate/client/src/backend.rs @@ -0,0 +1,53 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Polkadot Client data backend + +use state_machine; +use error; +use primitives::block; +use blockchain::{self, BlockId}; + +/// Block insertion transction. Keeps hold if the inseted block state and data. +pub trait BlockImportOperation { + /// Associated state backend type. + type State: state_machine::backend::Backend; + + /// Returns pending state. + fn state(&self) -> error::Result; + /// Append block data to the transaction. + fn import_block(&mut self, header: block::Header, body: Option, is_new_best: bool) -> error::Result<()>; +} + +/// Client backend. Manages the data layer. +pub trait Backend { + /// Associated block insertion transaction type. + type BlockImportOperation: BlockImportOperation; + /// Associated blockchain backend type. + type Blockchain: blockchain::Backend; + /// Associated state backend type. + type State: state_machine::backend::Backend; + + /// Begin a new block insertion transaction with given parent block id. + fn begin_transaction(&self, block: BlockId) -> error::Result; + /// Commit block insertion. + fn commit_transaction(&self, transaction: Self::BlockImportOperation) -> error::Result<()>; + /// Returns reference to blockchain backend. + fn blockchain(&self) -> &Self::Blockchain; + /// Returns state backend for specified block. + fn state_at(&self, block: BlockId) -> error::Result; +} + diff --git a/substrate/client/src/blockchain.rs b/substrate/client/src/blockchain.rs new file mode 100644 index 0000000000..d8881fe5cf --- /dev/null +++ b/substrate/client/src/blockchain.rs @@ -0,0 +1,86 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Polkadot blockchain trait + +use std::fmt::{Display, Formatter, Error as FmtError}; +use primitives::block; +use error::Result; + +/// Block indentification. +#[derive(Debug, Clone, Copy)] +pub enum BlockId { + /// Identify by block header hash. + Hash(block::HeaderHash), + /// Identify by block number. + Number(block::Number), +} + +impl Display for BlockId { + fn fmt(&self, f: &mut Formatter) -> ::std::result::Result<(), FmtError> { + match *self { + BlockId::Hash(h) => h.fmt(f), + BlockId::Number(n) => n.fmt(f), + } + } +} + +/// Blockchain database backend. Does not perform any validation. +pub trait Backend: Send + Sync { + /// Get block header. Returns `None` if block is not found. + fn header(&self, id: BlockId) -> Result>; + /// Get block body. Returns `None` if block is not found. + fn body(&self, id: BlockId) -> Result>; + /// Get blockchain info. + fn info(&self) -> Result; + /// Get block status. + fn status(&self, id: BlockId) -> Result; + /// Get block hash by number. Returns `None` if the header is not in the chain. + fn hash(&self, number: block::Number) -> Result>; +} + +/// Block import outcome +pub enum ImportResult { + /// Imported successfully. + Imported, + /// Block already exists, skippped. + AlreadyInChain, + /// Unknown parent. + UnknownParent, + /// Other errror. + Err(E), +} + +/// Blockchain info +#[derive(Debug)] +pub struct Info { + /// Best block hash. + pub best_hash: block::HeaderHash, + /// Best block number. + pub best_number: block::Number, + /// Genesis block hash. + pub genesis_hash: block::HeaderHash, +} + +/// Block status. +#[derive(Debug, PartialEq, Eq)] +pub enum BlockStatus { + /// Already in the blockchain. + InChain, + /// Not in the queue or the blockchain. + Unknown, +} + diff --git a/substrate/client/src/error.rs b/substrate/client/src/error.rs index b24b4753b1..0059804914 100644 --- a/substrate/client/src/error.rs +++ b/substrate/client/src/error.rs @@ -16,8 +16,9 @@ //! Polkadot client possible errors. -use primitives::block; +use std; use state_machine; +use blockchain; error_chain! { errors { @@ -28,7 +29,7 @@ error_chain! { } /// Unknown block. - UnknownBlock(h: block::HeaderHash) { + UnknownBlock(h: blockchain::BlockId) { description("unknown block"), display("UnknownBlock: {}", h), } @@ -38,6 +39,12 @@ error_chain! { description("execution error"), display("Execution: {}", e), } + + /// Blockchain error. + Blockchain(e: Box) { + description("Blockchain error"), + display("Blockchain: {}", e), + } } } @@ -47,3 +54,16 @@ impl From> for Error { ErrorKind::Execution(e).into() } } + +impl From for Error { + fn from(_e: state_machine::backend::Void) -> Self { + unreachable!() + } +} + +impl Error { + /// Chain a blockchain error. + pub fn from_blockchain(e: Box) -> Self { + ErrorKind::Blockchain(e).into() + } +} diff --git a/substrate/client/src/in_mem.rs b/substrate/client/src/in_mem.rs new file mode 100644 index 0000000000..cd8d7da6f9 --- /dev/null +++ b/substrate/client/src/in_mem.rs @@ -0,0 +1,204 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! In memory client backend + +use std::collections::HashMap; +use parking_lot::RwLock; +use state_machine; +use error; +use backend; +use primitives; +use ser; +use primitives::block::{self, HeaderHash}; +use blockchain::{self, BlockId, BlockStatus}; + +fn header_hash(header: &primitives::block::Header) -> primitives::block::HeaderHash { + primitives::hash(&ser::to_vec(header)) +} + +struct PendingBlock { + block: Block, + is_best: bool, +} + +struct Block { + header: block::Header, + body: Option, +} + +/// In-memory transaction. +pub struct BlockImportOperation { + pending_block: Option, + pending_state: state_machine::backend::InMemory, +} + +struct BlockchainStorage { + blocks: HashMap, + hashes: HashMap, + best_hash: HeaderHash, + best_number: block::Number, + genesis_hash: HeaderHash, +} + +/// In-memory blockchain. Supports concurrent reads. +pub struct Blockchain { + storage: RwLock, +} + +impl Blockchain { + fn id(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(h) => Some(h), + BlockId::Number(n) => self.storage.read().hashes.get(&n).cloned(), + } + } + + fn new() -> Blockchain { + Blockchain { + storage: RwLock::new( + BlockchainStorage { + blocks: HashMap::new(), + hashes: HashMap::new(), + best_hash: HeaderHash::default(), + best_number: 0, + genesis_hash: HeaderHash::default(), + }) + } + } + + fn insert(&self, hash: HeaderHash, header: block::Header, body: Option, is_new_best: bool) { + let number = header.number; + let mut storage = self.storage.write(); + storage.blocks.insert(hash, Block { + header: header, + body: body, + }); + storage.hashes.insert(number, hash); + if is_new_best { + storage.best_hash = hash; + storage.best_number = number; + } + if number == 0 { + storage.genesis_hash = hash; + } + } +} + +impl blockchain::Backend for Blockchain { + fn header(&self, id: BlockId) -> error::Result> { + Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).map(|b| b.header.clone()))) + } + + fn body(&self, id: BlockId) -> error::Result> { + Ok(self.id(id).and_then(|hash| self.storage.read().blocks.get(&hash).and_then(|b| b.body.clone()))) + } + + fn info(&self) -> error::Result { + let storage = self.storage.read(); + Ok(blockchain::Info { + best_hash: storage.best_hash, + best_number: storage.best_number, + genesis_hash: storage.genesis_hash, + }) + } + + fn status(&self, id: BlockId) -> error::Result { + match self.id(id).map_or(false, |hash| self.storage.read().blocks.contains_key(&hash)) { + true => Ok(BlockStatus::InChain), + false => Ok(BlockStatus::Unknown), + } + } + + fn hash(&self, number: block::Number) -> error::Result> { + Ok(self.id(BlockId::Number(number))) + } +} + +impl backend::BlockImportOperation for BlockImportOperation { + type State = state_machine::backend::InMemory; + + fn state(&self) -> error::Result { + Ok(self.pending_state.clone()) + } + + fn import_block(&mut self, header: block::Header, body: Option, is_new_best: bool) -> error::Result<()> { + assert!(self.pending_block.is_none(), "Only one block per transaction is allowed"); + self.pending_block = Some(PendingBlock { + block: Block { + header: header, + body: body, + }, + is_best: is_new_best, + }); + Ok(()) + } +} + +/// In-memory backend. Keeps all states and blocks in memory. Useful for testing. +pub struct Backend { + states: RwLock>, + blockchain: Blockchain, +} + +impl Backend { + /// Create a new instance of in-mem backend. + pub fn new() -> Backend { + Backend { + states: RwLock::new(HashMap::new()), + blockchain: Blockchain::new(), + } + } +} + +impl backend::Backend for Backend { + type BlockImportOperation = BlockImportOperation; + type Blockchain = Blockchain; + type State = state_machine::backend::InMemory; + + fn begin_transaction(&self, block: BlockId) -> error::Result { + let state = match block { + BlockId::Hash(h) if h.is_zero() => Self::State::default(), + _ => self.state_at(block)?, + }; + + Ok(BlockImportOperation { + pending_block: None, + pending_state: state, + }) + } + + fn commit_transaction(&self, transaction: Self::BlockImportOperation) -> error::Result<()> { + if let Some(pending_block) = transaction.pending_block { + let hash = header_hash(&pending_block.block.header); + self.states.write().insert(hash, transaction.pending_state); + self.blockchain.insert(hash, pending_block.block.header, pending_block.block.body, pending_block.is_best); + } + Ok(()) + } + + fn blockchain(&self) -> &Blockchain { + &self.blockchain + } + + fn state_at(&self, block: BlockId) -> error::Result { + match self.blockchain.id(block).and_then(|id| self.states.read().get(&id).cloned()) { + Some(state) => Ok(state), + None => Err(error::ErrorKind::UnknownBlock(block).into()), + } + } +} + diff --git a/substrate/client/src/lib.rs b/substrate/client/src/lib.rs index 242e12765e..2773085ece 100644 --- a/substrate/client/src/lib.rs +++ b/substrate/client/src/lib.rs @@ -20,28 +20,43 @@ extern crate polkadot_primitives as primitives; extern crate polkadot_state_machine as state_machine; +extern crate polkadot_serializer as ser; -#[macro_use] -extern crate error_chain; +extern crate parking_lot; +#[macro_use] extern crate error_chain; +#[macro_use] extern crate log; pub mod error; +pub mod blockchain; +pub mod backend; +pub mod in_mem; + +pub use blockchain::Info as ChainInfo; +pub use blockchain::BlockId; use primitives::{block}; use primitives::contract::{CallData, StorageKey, StorageData}; -use state_machine::backend::Backend; -use self::error::ResultExt; +use blockchain::Backend as BlockchainBackend; +use backend::BlockImportOperation; +use state_machine::backend::Backend as StateBackend; -/// Blockchain access -pub trait Blockchain { - /// Error Type - type Error; +/// Polkadot Client +#[derive(Debug)] +pub struct Client where B: backend::Backend { + backend: B, + executor: E, +} - /// Returns the hash of latest block. - fn latest_hash(&self) -> Result; - - /// Given a hash return a header - fn header(&self, hash: &block::HeaderHash) -> Result, Self::Error>; +/// Client info +#[derive(Debug)] +pub struct ClientInfo { + /// Best block hash. + pub chain: ChainInfo, + /// Best block number in the queue. + pub best_queued_number: Option, + /// Best queued block hash. + pub best_queued_hash: Option, } /// Information regarding the result of a call. @@ -52,39 +67,77 @@ pub struct CallResult { pub changes: state_machine::OverlayedChanges, } -/// Polkadot Client +/// Block import result. #[derive(Debug)] -pub struct Client { - blockchain: B, - executor: E, +pub enum ImportResult { + /// Added to the import queue. + Queued, + /// Already in the import queue. + AlreadyQueued, + /// Already in the blockchain. + AlreadyInChain, + /// Block or parent is known to be bad. + KnownBad, + /// Block parent is not in the chain. + UnknownParent, } -impl Client { - /// Creates new Polkadot Client with given blockchain and code executor. - pub fn new(blockchain: B, executor: E) -> Self { - Client { - blockchain, - executor, - } - } +/// Block status. +#[derive(Debug, PartialEq, Eq)] +pub enum BlockStatus { + /// Added to the import queue. + Queued, + /// Already in the blockchain. + InChain, + /// Block or parent is known to be bad. + KnownBad, + /// Not in the queue or the blockchain. + Unknown, +} + + +/// Create an instance of in-memory client. +pub fn new_in_mem(executor: E) -> error::Result> where E: state_machine::CodeExecutor { + Client::new(in_mem::Backend::new(), executor) } impl Client where - B: Blockchain, + B: backend::Backend, E: state_machine::CodeExecutor, + error::Error: From<<::State as state_machine::backend::Backend>::Error>, { + /// Creates new Polkadot Client with given blockchain and code executor. + pub fn new(backend: B, executor: E) -> error::Result { + if backend.blockchain().header(BlockId::Number(0))?.is_none() { + trace!("Empty database, writing genesis block"); + // TODO: spec + let genesis_header = block::Header { + parent_hash: Default::default(), + number: 0, + state_root: Default::default(), + parachain_activity: Default::default(), + logs: Default::default(), + }; - fn state_at(&self, _hash: &block::HeaderHash) -> error::Result { - // TODO [ToDr] Actually retrieve the state. - Ok(state_machine::backend::InMemory::default()) + let mut tx = backend.begin_transaction(BlockId::Hash(block::HeaderHash::default()))?; + tx.import_block(genesis_header, None, true)?; + backend.commit_transaction(tx)?; + } + Ok(Client { + backend, + executor, + }) + } + + fn state_at(&self, hash: &block::HeaderHash) -> error::Result { + self.backend.state_at(BlockId::Hash(*hash)) } /// Return single storage entry of contract under given address in state in a block of given hash. pub fn storage(&self, hash: &block::HeaderHash, key: &StorageKey) -> error::Result { - self.state_at(hash)? + Ok(self.state_at(hash)? .storage(&key.0) - .map(|x| StorageData(x.to_vec())) - .chain_err(|| error::ErrorKind::Backend) + .map(|x| StorageData(x.to_vec()))?) } /// Execute a call to a contract on top of state in a block of given hash. @@ -103,4 +156,52 @@ impl Client where )?; Ok(CallResult { return_data: vec![], changes }) } + + /// Queue a block for import. + pub fn import_block(&self, header: block::Header, body: Option) -> error::Result { + // TODO: import lock + // TODO: validate block + match self.backend.blockchain().status(BlockId::Hash(header.parent_hash))? { + blockchain::BlockStatus::InChain => (), + blockchain::BlockStatus::Unknown => return Ok(ImportResult::UnknownParent), + } + + let mut transaction = self.backend.begin_transaction(BlockId::Number(header.number))?; + let mut _state = transaction.state()?; + // TODO: execute block on _state + + let is_new_best = header.number == self.backend.blockchain().info()?.best_number + 1; + transaction.import_block(header, body, is_new_best)?; + self.backend.commit_transaction(transaction)?; + Ok(ImportResult::Queued) + } + + /// Get blockchain info. + pub fn info(&self) -> error::Result { + let info = self.backend.blockchain().info().map_err(|e| error::Error::from_blockchain(Box::new(e)))?; + Ok(ClientInfo { + chain: info, + best_queued_hash: None, + best_queued_number: None, + }) + } + + /// Get block status. + pub fn block_status(&self, hash: &block::HeaderHash) -> error::Result { + // TODO: more efficient implementation + match self.backend.blockchain().header(BlockId::Hash(*hash)).map_err(|e| error::Error::from_blockchain(Box::new(e)))?.is_some() { + true => Ok(BlockStatus::InChain), + false => Ok(BlockStatus::Unknown), + } + } + + /// Get block hash by number. + pub fn block_hash(&self, block_number: block::Number) -> error::Result> { + self.backend.blockchain().hash(block_number) + } + + /// Get block header by hash. + pub fn header(&self, hash: &block::HeaderHash) -> error::Result> { + self.backend.blockchain().header(BlockId::Hash(*hash)) + } } diff --git a/substrate/network/Cargo.toml b/substrate/network/Cargo.toml new file mode 100644 index 0000000000..4733ec2d70 --- /dev/null +++ b/substrate/network/Cargo.toml @@ -0,0 +1,29 @@ +[package] +description = "Polkadot network protocol" +name = "polkadot-network" +version = "0.1.0" +license = "GPL-3.0" +authors = ["Parity Technologies "] + +[lib] + +[dependencies] +ethcore-network = { git = "https://github.com/paritytech/parity.git" } +ethcore-io = { git = "https://github.com/paritytech/parity.git" } +polkadot-primitives = { path = "../primitives" } +polkadot-client = { path = "../client" } +polkadot-state-machine = { path = "../state_machine" } +polkadot-serializer = { path = "../serializer" } +log = "0.3" +env_logger = "0.4" +rand = "0.3" +heapsize = "0.4" +semver = "0.6" +smallvec = { version = "0.4", features = ["heapsizeof"] } +parking_lot = "0.4" +ipnetwork = "0.12" +error-chain = "0.11" +bitflags = "1.0" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/substrate/network/src/blocks.rs b/substrate/network/src/blocks.rs new file mode 100644 index 0000000000..52a72e022f --- /dev/null +++ b/substrate/network/src/blocks.rs @@ -0,0 +1,263 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use std::mem; +use std::cmp; +use std::ops::Range; +use std::collections::{HashMap, BTreeMap}; +use std::collections::hash_map::Entry; +use network::PeerId; +use primitives::block::{Number as BlockNumber}; +use message; + +const MAX_PARALLEL_DOWNLOADS: u32 = 1; + +/// Block data with origin. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BlockData { + pub block: message::BlockData, + pub origin: PeerId, +} + +#[derive(Debug)] +enum BlockRangeState { + Downloading { + len: BlockNumber, + downloading: u32, + }, + Complete(Vec), +} + +impl BlockRangeState { + pub fn len(&self) -> BlockNumber { + match *self { + BlockRangeState::Downloading { len, .. } => len, + BlockRangeState::Complete(ref blocks) => blocks.len() as BlockNumber, + } + } +} + +/// A collection of blocks being downloaded. +#[derive(Default)] +pub struct BlockCollection { + /// Downloaded blocks. + blocks: BTreeMap, + peer_requests: HashMap, +} + +impl BlockCollection { + /// Create a new instance. + pub fn new() -> BlockCollection { + BlockCollection { + blocks: BTreeMap::new(), + peer_requests: HashMap::new(), + } + } + + /// Clear everything. + pub fn clear(&mut self) { + self.blocks.clear(); + self.peer_requests.clear(); + } + + /// Insert a set of blocks into collection. + pub fn insert(&mut self, start: BlockNumber, blocks: Vec, peer_id: PeerId) { + if blocks.is_empty() { + return; + } + + match self.blocks.get(&start) { + Some(&BlockRangeState::Downloading { .. }) => { + trace!(target: "sync", "Ignored block data still marked as being downloaded: {}", start); + debug_assert!(false); + return; + }, + Some(&BlockRangeState::Complete(ref existing)) if existing.len() >= blocks.len() => { + trace!(target: "sync", "Ignored block data already downloaded: {}", start); + return; + }, + _ => (), + } + + self.blocks.insert(start, BlockRangeState::Complete(blocks.into_iter().map(|b| BlockData { origin: peer_id, block: b }).collect())); + } + + /// Returns a set of block hashes that require a header download. The returned set is marked as being downloaded. + pub fn needed_blocks(&mut self, peer_id: PeerId, count: usize, peer_best: BlockNumber, common: BlockNumber) -> Option> { + // First block number that we need to download + let first_different = common + 1; + let count = count as BlockNumber; + let (mut range, downloading) = { + let mut downloading_iter = self.blocks.iter().peekable(); + let mut prev: Option<(&BlockNumber, &BlockRangeState)> = None; + loop { + let next = downloading_iter.next(); + break match &(prev, next) { + &(Some((start, &BlockRangeState::Downloading { ref len, downloading })), _) if downloading < MAX_PARALLEL_DOWNLOADS => + (*start .. *start + *len, downloading), + &(Some((start, r)), Some((next_start, _))) if start + r.len() < *next_start => + (*start + r.len() .. cmp::min(*next_start, *start + count), 0), // gap + &(Some((start, r)), None) => + (start + r.len() .. start + r.len() + count, 0), // last range + &(None, None) => + (first_different .. first_different + count, 0), // empty + &(None, Some((start, _))) if *start > first_different => + (first_different .. cmp::min(first_different + count, *start), 0), // gap at the start + _ => { + prev = next; + continue + }, + } + } + }; + + // crop to peers best + if range.start >= peer_best { + return None; + } + range.end = cmp::min(peer_best, range.end); + + self.peer_requests.insert(peer_id, range.start); + self.blocks.insert(range.start, BlockRangeState::Downloading{ len: range.end - range.start, downloading: downloading + 1 }); + Some(range) + } + + /// Get a valid chain of blocks ordered in descending order and ready for importing into blockchain. + pub fn drain(&mut self, from: BlockNumber) -> Vec { + let mut drained = Vec::new(); + let mut ranges = Vec::new(); + { + let mut prev = from; + for (start, range_data) in &mut self.blocks { + match range_data { + &mut BlockRangeState::Complete(ref mut blocks) if *start <= prev => { + prev = *start + blocks.len() as BlockNumber; + let mut blocks = mem::replace(blocks, Vec::new()); + drained.append(&mut blocks); + ranges.push(*start); + }, + _ => break, + } + } + } + for r in ranges { + self.blocks.remove(&r); + } + trace!(target: "sync", "Drained {} blocks", drained.len()); + drained + } + + pub fn clear_peer_download(&mut self, peer_id: PeerId) { + match self.peer_requests.entry(peer_id) { + Entry::Occupied(entry) => { + let start = entry.remove(); + let remove = match self.blocks.get_mut(&start) { + Some(&mut BlockRangeState::Downloading { ref mut downloading, .. }) if *downloading > 1 => { + *downloading = *downloading - 1; + false + }, + Some(&mut BlockRangeState::Downloading { .. }) => { + true + }, + _ => { + debug_assert!(false); + false + } + }; + if remove { + self.blocks.remove(&start); + } + }, + _ => (), + } + } +} + +#[cfg(test)] +mod test { + use super::{BlockCollection, BlockData}; + use message; + use primitives::block::{HeaderHash}; + + fn is_empty(bc: &BlockCollection) -> bool { + bc.blocks.is_empty() && + bc.peer_requests.is_empty() + } + + fn generate_blocks(n: usize) -> Vec { + (0 .. n).map(|_| message::BlockData { + hash: HeaderHash::random(), + header: None, + body: None, + message_queue: None, + receipt: None, + }).collect() + } + + #[test] + fn create_clear() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + bc.insert(1, generate_blocks(100), 0); + assert!(!is_empty(&bc)); + bc.clear(); + assert!(is_empty(&bc)); + } + + #[test] + fn insert_blocks() { + let mut bc = BlockCollection::new(); + assert!(is_empty(&bc)); + let peer0 = 0; + let peer1 = 1; + let peer2 = 2; + + let blocks = generate_blocks(150); + assert_eq!(bc.needed_blocks(peer0, 40, 150, 0), Some(1 .. 41)); + assert_eq!(bc.needed_blocks(peer1, 40, 150, 0), Some(41 .. 81)); + assert_eq!(bc.needed_blocks(peer2, 40, 150, 0), Some(81 .. 121)); + + bc.clear_peer_download(peer1); + bc.insert(41, blocks[41..81].to_vec(), peer1); + assert_eq!(bc.drain(1), vec![]); + assert_eq!(bc.needed_blocks(peer1, 40, 150, 0), Some(121 .. 150)); + bc.clear_peer_download(peer0); + bc.insert(1, blocks[1..11].to_vec(), peer0); + + assert_eq!(bc.needed_blocks(peer0, 40, 150, 0), Some(11 .. 41)); + assert_eq!(bc.drain(1), blocks[1..11].iter().map(|b| BlockData { block: b.clone(), origin: 0 }).collect::>()); + + bc.clear_peer_download(peer0); + bc.insert(11, blocks[11..41].to_vec(), peer0); + + let drained = bc.drain(12); + assert_eq!(drained[..30], blocks[11..41].iter().map(|b| BlockData { block: b.clone(), origin: 0 }).collect::>()[..]); + assert_eq!(drained[30..], blocks[41..81].iter().map(|b| BlockData { block: b.clone(), origin: 1 }).collect::>()[..]); + + bc.clear_peer_download(peer2); + assert_eq!(bc.needed_blocks(peer2, 40, 150, 80), Some(81 .. 121)); + bc.clear_peer_download(peer2); + bc.insert(81, blocks[81..121].to_vec(), peer2); + bc.clear_peer_download(peer1); + bc.insert(121, blocks[121..150].to_vec(), peer1); + + assert_eq!(bc.drain(80), vec![]); + let drained = bc.drain(81); + assert_eq!(drained[..40], blocks[81..121].iter().map(|b| BlockData { block: b.clone(), origin: 2 }).collect::>()[..]); + assert_eq!(drained[40..], blocks[121..150].iter().map(|b| BlockData { block: b.clone(), origin: 1 }).collect::>()[..]); + } +} + diff --git a/substrate/network/src/chain.rs b/substrate/network/src/chain.rs new file mode 100644 index 0000000000..c125434710 --- /dev/null +++ b/substrate/network/src/chain.rs @@ -0,0 +1,59 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Blockchain access trait + +use client::{self, Client as PolkadotClient, ImportResult, ClientInfo, BlockStatus}; +use client::error::Error; +use state_machine; +use primitives::block; + +pub trait Client : Send + Sync { + /// Given a hash return a header + fn import(&self, header: block::Header, body: Option) -> Result; + + /// Get blockchain info. + fn info(&self) -> Result; + + /// Get block status. + fn block_status(&self, hash: &block::HeaderHash) -> Result; + + /// Get block hash by number. + fn block_hash(&self, block_number: block::Number) -> Result, Error>; +} + +impl Client for PolkadotClient where + B: client::backend::Backend + Send + Sync + 'static, + E: state_machine::CodeExecutor + Send + Sync + 'static, +{ + fn import(&self, header: block::Header, body: Option) -> Result { + (self as &Client).import(header, body) + } + + fn info(&self) -> Result { + (self as &Client).info() + } + + fn block_status(&self, hash: &block::HeaderHash) -> Result { + (self as &Client).block_status(hash) + } + + fn block_hash(&self, block_number: block::Number) -> Result, Error> { + (self as &Client).block_hash(block_number) + } +} + + diff --git a/substrate/network/src/config.rs b/substrate/network/src/config.rs new file mode 100644 index 0000000000..b826213280 --- /dev/null +++ b/substrate/network/src/config.rs @@ -0,0 +1,30 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use service::Role; + +/// Protocol configuration +pub struct ProtocolConfig { + pub roles: Role, +} + +impl Default for ProtocolConfig { + fn default() -> ProtocolConfig { + ProtocolConfig { + roles: Role::FULL, + } + } +} diff --git a/substrate/rpc/src/test_helpers.rs b/substrate/network/src/error.rs similarity index 54% rename from substrate/rpc/src/test_helpers.rs rename to substrate/network/src/error.rs index 6d2e23485b..9583a29861 100644 --- a/substrate/rpc/src/test_helpers.rs +++ b/substrate/network/src/error.rs @@ -12,34 +12,20 @@ // GNU General Public License for more details. // You should have received a copy of the GNU General Public License -// along with Polkadot. If not, see . +// along with Polkadot. If not, see .? +use network::Error as NetworkError; use client; -use primitives::{block, parachain}; -/// Temporary dummy blockchain implementation for tests. -#[derive(Debug, Default)] -pub struct Blockchain; - -impl client::Blockchain for Blockchain { - type Error = ::std::io::Error; - - fn latest_hash(&self) -> Result { - Ok(0.into()) +error_chain! { + foreign_links { + Network(NetworkError) #[doc = "Devp2p error."]; } - fn header(&self, hash: &block::HeaderHash) -> Result, Self::Error> { - Ok(if hash != &0.into() { - None - } else { - Some(block::Header { - parent_hash: 0.into(), - number: 0, - state_root: 0.into(), - parachain_activity: parachain::Activity(vec![0]), - logs: vec![], - }) - }) + links { + Client(client::error::Error, client::error::ErrorKind); + } + + errors { } } - diff --git a/substrate/network/src/io.rs b/substrate/network/src/io.rs new file mode 100644 index 0000000000..339e80e9ad --- /dev/null +++ b/substrate/network/src/io.rs @@ -0,0 +1,78 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use network::{NetworkContext, PeerId, Error as NetworkError, SessionInfo}; + +/// IO interface for the syncing handler. +/// Provides peer connection management and an interface to the blockchain client. +pub trait SyncIo { + /// Disable a peer + fn disable_peer(&mut self, peer_id: PeerId); + /// Disconnect peer + fn disconnect_peer(&mut self, peer_id: PeerId); + /// Send a packet to a peer. + fn send(&mut self, peer_id: PeerId, data: Vec) -> Result<(), NetworkError>; + /// Returns peer identifier string + fn peer_info(&self, peer_id: PeerId) -> String { + peer_id.to_string() + } + /// Returns information on p2p session + fn peer_session_info(&self, peer_id: PeerId) -> Option; + /// Check if the session is expired + fn is_expired(&self) -> bool; +} + +/// Wraps `NetworkContext` and the blockchain client +pub struct NetSyncIo<'s, 'h> where 'h: 's { + network: &'s NetworkContext<'h>, +} + +impl<'s, 'h> NetSyncIo<'s, 'h> { + /// Creates a new instance from the `NetworkContext` and the blockchain client reference. + pub fn new(network: &'s NetworkContext<'h>) -> NetSyncIo<'s, 'h> { + NetSyncIo { + network: network, + } + } +} + +impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> { + fn disable_peer(&mut self, peer_id: PeerId) { + self.network.disable_peer(peer_id); + } + + fn disconnect_peer(&mut self, peer_id: PeerId) { + self.network.disconnect_peer(peer_id); + } + + fn send(&mut self, peer_id: PeerId, data: Vec) -> Result<(), NetworkError>{ + self.network.send(peer_id, 0, data) + } + + fn peer_session_info(&self, peer_id: PeerId) -> Option { + self.network.session_info(peer_id) + } + + fn is_expired(&self) -> bool { + self.network.is_expired() + } + + fn peer_info(&self, peer_id: PeerId) -> String { + self.network.peer_client_version(peer_id) + } +} + + diff --git a/substrate/network/src/lib.rs b/substrate/network/src/lib.rs new file mode 100644 index 0000000000..10a6eb6065 --- /dev/null +++ b/substrate/network/src/lib.rs @@ -0,0 +1,62 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +#![warn(missing_docs)] + +//! Implements polkadot protocol version as specified here: +//! https://github.com/paritytech/polkadot/wiki/Network-protocol + +extern crate ethcore_network as network; +extern crate ethcore_io as core_io; +extern crate env_logger; +extern crate rand; +extern crate semver; +extern crate parking_lot; +extern crate smallvec; +extern crate ipnetwork; +extern crate polkadot_primitives as primitives; +extern crate polkadot_client as client; +extern crate polkadot_state_machine as state_machine; +extern crate polkadot_serializer as ser; +extern crate serde; +extern crate serde_json; +#[macro_use] extern crate serde_derive; +#[macro_use] extern crate log; +#[macro_use] extern crate bitflags; +#[macro_use] extern crate error_chain; + +mod service; +mod sync; +mod protocol; +mod io; +mod message; +mod error; +mod config; +mod chain; +mod blocks; + +#[cfg(test)] +mod test; + +pub use service::Service; +pub use protocol::{ProtocolStatus}; +pub use network::{NonReservedPeerMode, ConnectionFilter, ConnectionDirection, NetworkConfiguration}; + +// TODO: move it elsewhere +fn header_hash(header: &primitives::block::Header) -> primitives::block::HeaderHash { + primitives::hash(&ser::to_vec(header)) +} + diff --git a/substrate/network/src/message.rs b/substrate/network/src/message.rs new file mode 100644 index 0000000000..ff0c678b0b --- /dev/null +++ b/substrate/network/src/message.rs @@ -0,0 +1,189 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +//! Network packet message types. These get serialized and put into the lower level protocol payload. + +use std::borrow::Borrow; +use primitives::parachain::Id as ParachainId; +use primitives::Address; +use primitives::block::{Number as BlockNumber, HeaderHash, Header, Body}; +use service::Role as RoleFlags; + +pub type RequestId = u64; +type Bytes = Vec; + +type Signature = ::primitives::hash::H256; //TODO: + +/// Configured node role. +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum Role { + /// Full relay chain client with no additional responsibilities. + Full, + /// Relay chain light client. + Light, + /// Parachain validator. + Validator, + /// Parachain collator. + Collator, +} + +impl From for RoleFlags where T: Borrow<[Role]> { + fn from(roles: T) -> RoleFlags { + let mut flags = RoleFlags::NONE; + let roles: &[Role] = roles.borrow(); + for r in roles { + match *r { + Role::Full => flags = flags | RoleFlags::FULL, + Role::Light => flags = flags | RoleFlags::LIGHT, + Role::Validator => flags = flags | RoleFlags::VALIDATOR, + Role::Collator => flags = flags | RoleFlags::COLLATOR, + } + } + flags + } +} + +impl From for Vec where { + fn from(flags: RoleFlags) -> Vec { + let mut roles = Vec::new(); + if !(flags & RoleFlags::FULL).is_empty() { + roles.push(Role::Full); + } + if !(flags & RoleFlags::LIGHT).is_empty() { + roles.push(Role::Light); + } + if !(flags & RoleFlags::VALIDATOR).is_empty() { + roles.push(Role::Validator); + } + if !(flags & RoleFlags::COLLATOR).is_empty() { + roles.push(Role::Collator); + } + roles + } +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Copy, Clone)] +/// Bits of block data and associated artefacts to request. +pub enum BlockAttribute { + /// Include block header. + Header, + /// Include block body. + Body, + /// Include block receipt. + Receipt, + /// Include block message queue. + MessageQueue, +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +/// Block data sent in the response. +pub struct BlockData { + /// Block header hash. + pub hash: HeaderHash, + /// Block header if requested. + pub header: Option
, + /// Block body if requested. + pub body: Option, + /// Block receipt if requested. + pub receipt: Option, + /// Block message queue if requested. + pub message_queue: Option, +} + +#[serde(untagged)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +/// Identifies starting point of a block sequence. +pub enum FromBlock { + /// Start with given hash. + Hash(HeaderHash), + /// Start with given block number. + Number(BlockNumber), +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +/// Block enumeration direction. +pub enum Direction { + /// Enumerate in ascending order (from child to parent). + Ascending, + /// Enumerate in descendfing order (from parent to canonical child). + Descending, +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +/// A network message. +pub enum Message { + /// Status packet. + Status(Status), + /// Block request. + BlockRequest(BlockRequest), + /// Block response. + BlockResponse(BlockResponse), + /// Block announce. + BlockAnnounce(BlockAnnounce), +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct Status { + /// Protocol version. + pub version: u32, + /// Supported roles. + pub roles: Vec, + /// Best block number. + pub best_number: BlockNumber, + /// Best block hash. + pub best_hash: HeaderHash, + /// Genesis block hash. + pub genesis_hash: HeaderHash, + /// Signatue of `best_hash` made with validator address. Required for the validator role. + pub validator_signature: Option, + /// Validator address. Required for the validator role. + pub validator_id: Option
, + /// Parachain id. Required for the collator role. + pub parachain_id: Option, +} + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +/// Request block data from a peer. +pub struct BlockRequest { + /// Unique request id. + pub id: RequestId, + /// Bits of block data to request. + pub fields: Vec, + /// Start from this block. + pub from: FromBlock, + /// End at this block. An implementation defined maximum is used when unspecified. + pub to: Option, + /// Sequence direction. + pub direction: Direction, + /// Maximum number of block to return. An implementation defined maximum is used when unspecified. + pub max: Option, +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +/// Response to `BlockRequest` +pub struct BlockResponse { + /// Id of a request this response was made for. + pub id: RequestId, + /// Block data for the requested sequence. + pub blocks: Vec, +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +/// Announce a new complete relay chain block on the network. +pub struct BlockAnnounce { + /// New block header. + pub header: Header, +} diff --git a/substrate/network/src/protocol.rs b/substrate/network/src/protocol.rs new file mode 100644 index 0000000000..3b0a5a801a --- /dev/null +++ b/substrate/network/src/protocol.rs @@ -0,0 +1,347 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use std::collections::{HashMap, HashSet, BTreeMap}; +use std::mem; +use std::sync::Arc; +use parking_lot::RwLock; +use serde_json; +use std::time; +use primitives::block::{HeaderHash, TransactionHash, Number as BlockNumber, Header}; +use network::{PeerId, NodeId}; + +use message::{self, Message}; +use sync::{ChainSync, Status as SyncStatus}; +use service::Role; +use config::ProtocolConfig; +use chain::Client; +use io::SyncIo; +use error; + +const REQUEST_TIMEOUT_SEC: u64 = 15; +const PROTOCOL_VERSION: u32 = 0; + +// Lock must always be taken in order declared here. +pub struct Protocol { + config: ProtocolConfig, + chain: Arc, + genesis_hash: HeaderHash, + sync: RwLock, + /// All connected peers + peers: RwLock>, + /// Connected peers pending Status message. + handshaking_peers: RwLock>, +} + +/// Syncing status and statistics +#[derive(Clone, Copy)] +pub struct ProtocolStatus { + /// Sync status. + pub sync: SyncStatus, + /// Total number of connected peers + pub num_peers: usize, + /// Total number of active peers. + pub num_active_peers: usize, +} + +/// Peer information +struct Peer { + /// Protocol version + protocol_version: u32, + /// Roles + roles: Role, + /// Peer best block hash + best_hash: HeaderHash, + /// Peer best block number + best_number: BlockNumber, + /// Pending block request if any + block_request: Option, + /// Request timestamp + request_timestamp: Option, + /// Holds a set of transactions recently sent to this peer to avoid spamming. + _last_sent_transactions: HashSet, + /// Request counter, + request_id: message::RequestId, +} + +#[derive(Debug)] +pub struct PeerInfo { + /// Roles + pub roles: Role, + /// Protocol version + pub protocol_version: u32, + /// Peer best block hash + pub best_hash: HeaderHash, + /// Peer best block number + pub best_number: BlockNumber, +} + +/// Transaction stats +#[derive(Debug)] +pub struct TransactionStats { + /// Block number where this TX was first seen. + pub first_seen: u64, + /// Peers it was propagated to. + pub propagated_to: BTreeMap, +} + +impl Protocol { + /// Create a new instance. + pub fn new(config: ProtocolConfig, chain: Arc) -> error::Result { + let info = chain.info()?; + let protocol = Protocol { + config: config, + chain: chain, + genesis_hash: info.chain.genesis_hash, + sync: RwLock::new(ChainSync::new(&info)), + peers: RwLock::new(HashMap::new()), + handshaking_peers: RwLock::new(HashMap::new()), + }; + Ok(protocol) + } + + /// Returns protocol status + pub fn status(&self) -> ProtocolStatus { + let sync = self.sync.read(); + let peers = self.peers.read(); + ProtocolStatus { + sync: sync.status(), + num_peers: peers.values().count(), + num_active_peers: peers.values().filter(|p| p.block_request.is_some()).count(), + } + } + + pub fn handle_packet(&self, io: &mut SyncIo, peer_id: PeerId, data: &[u8]) { + let message: Message = match serde_json::from_slice(data) { + Ok(m) => m, + Err(e) => { + debug!("Invalid packet from {}: {}", peer_id, e); + io.disable_peer(peer_id); + return; + } + }; + + match message { + Message::Status(s) => self.on_status_message(io, peer_id, s), + Message::BlockRequest(r) => self.on_block_request(io, peer_id, r), + Message::BlockResponse(r) => { + let request = { + let mut peers = self.peers.write(); + if let Some(ref mut peer) = peers.get_mut(&peer_id) { + peer.request_timestamp = None; + match mem::replace(&mut peer.block_request, None) { + Some(r) => r, + None => { + debug!("Unexpected response packet from {}", peer_id); + io.disable_peer(peer_id); + return; + } + } + } else { + debug!("Unexpected packet from {}", peer_id); + io.disable_peer(peer_id); + return; + } + }; + if request.id != r.id { + trace!("Ignoring mismatched response packet from {}", peer_id); + return; + } + self.on_block_response(io, peer_id, request, r); + }, + Message::BlockAnnounce(announce) => { + self.on_block_announce(io, peer_id, announce); + } + } + } + + pub fn send_message(&self, io: &mut SyncIo, peer_id: PeerId, mut message: Message) { + let mut peers = self.peers.write(); + if let Some(ref mut peer) = peers.get_mut(&peer_id) { + match &mut message { + &mut Message::BlockRequest(ref mut r) => { + peer.block_request = Some(r.clone()); + peer.request_timestamp = Some(time::Instant::now()); + r.id = peer.request_id; + peer.request_id = peer.request_id + 1; + }, + _ => (), + } + } + let data = serde_json::to_vec(&message).expect("Serializer is infallible; qed"); + if let Err(e) = io.send(peer_id, data) { + debug!(target:"sync", "Error sending message: {:?}", e); + io.disconnect_peer(peer_id); + } + } + + /// Called when a new peer is connected + pub fn on_peer_connected(&self, io: &mut SyncIo, peer_id: PeerId) { + trace!(target: "sync", "Connected {}: {}", peer_id, io.peer_info(peer_id)); + self.handshaking_peers.write().insert(peer_id, time::Instant::now()); + self.send_status(io, peer_id); + } + + /// Called by peer when it is disconnecting + pub fn on_peer_disconnected(&self, io: &mut SyncIo, peer: PeerId) { + trace!(target: "sync", "Disconnecting {}: {}", peer, io.peer_info(peer)); + let removed = { + let mut peers = self.peers.write(); + let mut handshaking_peers = self.handshaking_peers.write(); + handshaking_peers.remove(&peer); + peers.remove(&peer).is_some() + }; + if removed { + self.sync.write().peer_disconnected(io, self, peer); + } + } + + pub fn on_block_request(&self, _io: &mut SyncIo, _peer_id: PeerId, _request: message::BlockRequest) { + } + + pub fn on_block_response(&self, io: &mut SyncIo, peer_id: PeerId, request: message::BlockRequest, response: message::BlockResponse) { + // TODO: validate response + self.sync.write().on_block_data(io, self, peer_id, request, response); + } + + pub fn tick(&self, io: &mut SyncIo) { + self.maintain_peers(io); + } + + fn maintain_peers(&self, io: &mut SyncIo) { + let tick = time::Instant::now(); + let mut aborting = Vec::new(); + { + let peers = self.peers.read(); + let handshaking_peers = self.handshaking_peers.read(); + for (peer_id, timestamp) in peers.iter() + .filter_map(|(id, peer)| peer.request_timestamp.as_ref().map(|r| (id, r))) + .chain(handshaking_peers.iter()) { + if (tick - *timestamp).as_secs() > REQUEST_TIMEOUT_SEC { + trace!(target:"sync", "Timeout {}", peer_id); + io.disconnect_peer(*peer_id); + aborting.push(*peer_id); + } + } + } + for p in aborting { + self.on_peer_disconnected(io, p); + } + } + + pub fn peer_info(&self, peer: PeerId) -> Option { + self.peers.read().get(&peer).map(|p| { + PeerInfo { + roles: p.roles, + protocol_version: p.protocol_version, + best_hash: p.best_hash, + best_number: p.best_number, + } + }) + } + + /// Called by peer to report status + fn on_status_message(&self, io: &mut SyncIo, peer_id: PeerId, status: message::Status) { + trace!(target: "sync", "New peer {} {:?}", peer_id, status); + if io.is_expired() { + trace!(target: "sync", "Status packet from expired session {}:{}", peer_id, io.peer_info(peer_id)); + return; + } + + { + let mut peers = self.peers.write(); + let mut handshaking_peers = self.handshaking_peers.write(); + if peers.contains_key(&peer_id) { + debug!(target: "sync", "Unexpected status packet from {}:{}", peer_id, io.peer_info(peer_id)); + return; + } + if status.genesis_hash != self.genesis_hash { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} genesis hash mismatch (ours: {}, theirs: {})", peer_id, self.genesis_hash, status.genesis_hash); + return; + } + if status.version != PROTOCOL_VERSION { + io.disable_peer(peer_id); + trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, status.version); + return; + } + + let peer = Peer { + protocol_version: status.version, + roles: status.roles.into(), + best_hash: status.best_hash, + best_number: status.best_number, + block_request: None, + request_timestamp: None, + _last_sent_transactions: HashSet::new(), + request_id: 0, + }; + peers.insert(peer_id.clone(), peer); + handshaking_peers.remove(&peer_id); + debug!(target: "sync", "Connected {} {}", peer_id, io.peer_info(peer_id)); + } + self.sync.write().new_peer(io, self, peer_id); + } + + /// Send Status message + fn send_status(&self, io: &mut SyncIo, peer_id: PeerId) { + if let Ok(info) = self.chain.info() { + let status = message::Status { + version: PROTOCOL_VERSION, + genesis_hash: info.chain.genesis_hash, + roles: self.config.roles.into(), + best_number: info.chain.best_number, + best_hash: info.chain.best_hash, + validator_signature: None, + validator_id: None, + parachain_id: None, + }; + self.send_message(io, peer_id, Message::Status(status)) + } + } + + pub fn abort(&self) { + let mut sync = self.sync.write(); + let mut peers = self.peers.write(); + let mut handshaking_peers = self.handshaking_peers.write(); + sync.clear(); + peers.clear(); + handshaking_peers.clear(); + } + + pub fn on_block_announce(&self, io: &mut SyncIo, peer_id: PeerId, announce: message::BlockAnnounce) { + let header = announce.header; + self.sync.write().on_block_announce(io, self, peer_id, &header); + } + + pub fn on_block_imported(&self, header: &Header) { + self.sync.write().update_chain_info(&header); + } + + pub fn on_new_transactions(&self) { + } + + pub fn transactions_stats(&self) -> BTreeMap { + BTreeMap::new() + } + + pub fn chain(&self) -> &Client { + &*self.chain + } +} + + + diff --git a/substrate/network/src/service.rs b/substrate/network/src/service.rs new file mode 100644 index 0000000000..11b4cae18e --- /dev/null +++ b/substrate/network/src/service.rs @@ -0,0 +1,239 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use std::sync::Arc; +use std::collections::{BTreeMap}; +use std::io; +use network::{NetworkProtocolHandler, NetworkService, NetworkContext, HostInfo, PeerId, ProtocolId, +NetworkConfiguration , NonReservedPeerMode, ErrorKind}; +use primitives::block::{TransactionHash, Header}; +use core_io::{TimerToken}; +use io::NetSyncIo; +use protocol::{Protocol, ProtocolStatus, PeerInfo as ProtocolPeerInfo, TransactionStats}; +use config::{ProtocolConfig}; +use error::Error; +use chain::Client; + +/// Polkadot devp2p protocol id +pub const DOT_PROTOCOL_ID: ProtocolId = *b"dot"; + +bitflags! { + pub struct Role: u32 { + const NONE = 0b00000000; + const FULL = 0b00000001; + const LIGHT = 0b00000010; + const VALIDATOR = 0b00000100; + const COLLATOR = 0b00001000; + } +} + +/// Sync status +pub trait SyncProvider: Send + Sync { + /// Get sync status + fn status(&self) -> ProtocolStatus; + /// Get peers information + fn peers(&self) -> Vec; + /// Get this node id if available. + fn node_id(&self) -> Option; + /// Returns propagation count for pending transactions. + fn transactions_stats(&self) -> BTreeMap; +} + +/// Peer connection information +#[derive(Debug)] +pub struct PeerInfo { + /// Public node id + pub id: Option, + /// Node client ID + pub client_version: String, + /// Capabilities + pub capabilities: Vec, + /// Remote endpoint address + pub remote_address: String, + /// Local endpoint address + pub local_address: String, + /// Dot protocol info. + pub dot_info: Option, +} + +/// Service initialization parameters. +pub struct Params { + /// Configuration. + pub config: ProtocolConfig, + /// Network layer configuration. + pub network_config: NetworkConfiguration, + /// Polkadot relay chain access point. + pub chain: Arc, +} + +/// Polkadot network service. Handles network IO and manages connectivity. +pub struct Service { + /// Network service + network: NetworkService, + /// Devp2p protocol handler + handler: Arc, +} + +impl Service { + /// Creates and register protocol with the network service + pub fn new(params: Params) -> Result, Error> { + + let service = NetworkService::new(params.network_config.clone(), None)?; + + let sync = Arc::new(Service { + network: service, + handler: Arc::new(ProtocolHandler { + protocol: Protocol::new(params.config, params.chain.clone())?, + }), + }); + + Ok(sync) + } + + /// Called when a new block is imported by the client. + pub fn on_block_imported(&self, header: &Header) { + self.handler.protocol.on_block_imported(header) + } + + /// Called when new transactons are imported by the client. + pub fn on_new_transactions(&self) { + self.handler.protocol.on_new_transactions() + } + + fn start(&self) { + match self.network.start().map_err(Into::into) { + Err(ErrorKind::Io(ref e)) if e.kind() == io::ErrorKind::AddrInUse => + warn!("Network port {:?} is already in use, make sure that another instance of Polkadot client is not running or change the port using the --port option.", self.network.config().listen_address.expect("Listen address is not set.")), + Err(err) => warn!("Error starting network: {}", err), + _ => {}, + }; + self.network.register_protocol(self.handler.clone(), DOT_PROTOCOL_ID, 1, &[0u8]) + .unwrap_or_else(|e| warn!("Error registering polkadot protocol: {:?}", e)); + } + + fn stop(&self) { + self.handler.protocol.abort(); + self.network.stop().unwrap_or_else(|e| warn!("Error stopping network: {:?}", e)); + } +} + +impl SyncProvider for Service { + /// Get sync status + fn status(&self) -> ProtocolStatus { + self.handler.protocol.status() + } + + /// Get sync peers + fn peers(&self) -> Vec { + self.network.with_context_eval(DOT_PROTOCOL_ID, |ctx| { + let peer_ids = self.network.connected_peers(); + + peer_ids.into_iter().filter_map(|peer_id| { + let session_info = match ctx.session_info(peer_id) { + None => return None, + Some(info) => info, + }; + + Some(PeerInfo { + id: session_info.id.map(|id| id.hex()), + client_version: session_info.client_version, + capabilities: session_info.peer_capabilities.into_iter().map(|c| c.to_string()).collect(), + remote_address: session_info.remote_address, + local_address: session_info.local_address, + dot_info: self.handler.protocol.peer_info(peer_id), + }) + }).collect() + }).unwrap_or_else(Vec::new) + } + + fn node_id(&self) -> Option { + self.network.external_url() + } + + fn transactions_stats(&self) -> BTreeMap { + self.handler.protocol.transactions_stats() + } +} + +struct ProtocolHandler { + /// Protocol handler + protocol: Protocol, +} + +impl NetworkProtocolHandler for ProtocolHandler { + fn initialize(&self, io: &NetworkContext, _host_info: &HostInfo) { + io.register_timer(0, 1000).expect("Error registering sync timer"); + } + + fn read(&self, io: &NetworkContext, peer: &PeerId, _packet_id: u8, data: &[u8]) { + self.protocol.handle_packet(&mut NetSyncIo::new(io), *peer, data); + } + + fn connected(&self, io: &NetworkContext, peer: &PeerId) { + self.protocol.on_peer_connected(&mut NetSyncIo::new(io), *peer); + } + + fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { + self.protocol.on_peer_disconnected(&mut NetSyncIo::new(io), *peer); + } + + fn timeout(&self, io: &NetworkContext, _timer: TimerToken) { + self.protocol.tick(&mut NetSyncIo::new(io)); + } +} + +/// Trait for managing network +pub trait ManageNetwork : Send + Sync { + /// Set to allow unreserved peers to connect + fn accept_unreserved_peers(&self); + /// Set to deny unreserved peers to connect + fn deny_unreserved_peers(&self); + /// Remove reservation for the peer + fn remove_reserved_peer(&self, peer: String) -> Result<(), String>; + /// Add reserved peer + fn add_reserved_peer(&self, peer: String) -> Result<(), String>; + /// Start network + fn start_network(&self); + /// Stop network + fn stop_network(&self); +} + + +impl ManageNetwork for Service { + fn accept_unreserved_peers(&self) { + self.network.set_non_reserved_mode(NonReservedPeerMode::Accept); + } + + fn deny_unreserved_peers(&self) { + self.network.set_non_reserved_mode(NonReservedPeerMode::Deny); + } + + fn remove_reserved_peer(&self, peer: String) -> Result<(), String> { + self.network.remove_reserved_peer(&peer).map_err(|e| format!("{:?}", e)) + } + + fn add_reserved_peer(&self, peer: String) -> Result<(), String> { + self.network.add_reserved_peer(&peer).map_err(|e| format!("{:?}", e)) + } + + fn start_network(&self) { + self.start(); + } + + fn stop_network(&self) { + self.stop(); + } +} diff --git a/substrate/network/src/sync.rs b/substrate/network/src/sync.rs new file mode 100644 index 0000000000..ec5b1ee67b --- /dev/null +++ b/substrate/network/src/sync.rs @@ -0,0 +1,372 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see .? + +use std::collections::HashMap; +use io::SyncIo; +use protocol::Protocol; +use network::PeerId; +use client::{ImportResult, BlockStatus, ClientInfo}; +use primitives::block::{HeaderHash, Number as BlockNumber, Header}; +use blocks::{self, BlockCollection}; +use message::{self, Message}; +use super::header_hash; + +// Maximum parallel requests for a block. +const MAX_BLOCK_DOWNLOAD: usize = 1; + +struct PeerSync { + pub common_hash: HeaderHash, + pub common_number: BlockNumber, + pub best_hash: HeaderHash, + pub best_number: BlockNumber, + pub state: PeerSyncState, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum PeerSyncState { + AncestorSearch(BlockNumber), + Available, + DownloadingNew(BlockNumber), + DownloadingStale(HeaderHash), +} + +/// Relay chain sync strategy. +pub struct ChainSync { + genesis_hash: HeaderHash, + peers: HashMap, + blocks: BlockCollection, + best_queued_number: BlockNumber, + best_queued_hash: HeaderHash, + required_block_attributes: Vec, +} + +/// Syncing status and statistics +#[derive(Clone, Copy)] +pub struct Status; + +impl ChainSync { + pub fn new(info: &ClientInfo) -> ChainSync { + ChainSync { + genesis_hash: info.chain.genesis_hash, + peers: HashMap::new(), + blocks: BlockCollection::new(), + best_queued_hash: info.best_queued_hash.unwrap_or(info.chain.best_hash), + best_queued_number: info.best_queued_number.unwrap_or(info.chain.best_number), + required_block_attributes: vec![message::BlockAttribute::Header, message::BlockAttribute::Body], + } + } + + /// Returns sync status + pub fn status(&self) -> Status { + Status + } + + pub fn new_peer(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId) { + if let Some(info) = protocol.peer_info(peer_id) { + match (protocol.chain().block_status(&info.best_hash), info.best_number) { + (Err(e), _) => { + debug!(target:"sync", "Error reading blockchain: {:?}", e); + io.disconnect_peer(peer_id); + }, + (Ok(BlockStatus::KnownBad), _) => { + debug!(target:"sync", "New peer with known bad best block {} ({}).", info.best_hash, info.best_number); + io.disable_peer(peer_id); + }, + (Ok(BlockStatus::Unknown), 0) => { + debug!(target:"sync", "New peer with unkown genesis hash {} ({}).", info.best_hash, info.best_number); + io.disable_peer(peer_id); + }, + (Ok(BlockStatus::Unknown), _) => { + debug!(target:"sync", "New peer with unkown best hash {} ({}), searching for common ancestor.", info.best_hash, info.best_number); + self.peers.insert(peer_id, PeerSync { + common_hash: self.genesis_hash, + common_number: 0, + best_hash: info.best_hash, + best_number: info.best_number, + state: PeerSyncState::AncestorSearch(info.best_number - 1), + }); + Self::request_ancestry(io, protocol, peer_id, info.best_number - 1) + }, + (Ok(BlockStatus::Queued), _) | (Ok(BlockStatus::InChain), _) => { + debug!(target:"sync", "New peer with known best hash {} ({}).", info.best_hash, info.best_number); + self.peers.insert(peer_id, PeerSync { + common_hash: info.best_hash, + common_number: info.best_number, + best_hash: info.best_hash, + best_number: info.best_number, + state: PeerSyncState::Available, + }); + } + } + } + } + + pub fn on_block_data(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, _request: message::BlockRequest, response: message::BlockResponse) { + let count = response.blocks.len(); + let mut imported: usize = 0; + let new_blocks = if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + match peer.state { + PeerSyncState::DownloadingNew(start_block) => { + self.blocks.clear_peer_download(peer_id); + peer.state = PeerSyncState::Available; + + self.blocks.insert(start_block, response.blocks, peer_id); + self.blocks.drain(self.best_queued_number + 1) + }, + PeerSyncState::DownloadingStale(_) => { + peer.state = PeerSyncState::Available; + response.blocks.into_iter().map(|b| blocks::BlockData { + origin: peer_id, + block: b + }).collect() + }, + PeerSyncState::AncestorSearch(n) => { + match response.blocks.get(0) { + Some(ref block) => { + match protocol.chain().block_hash(n) { + Ok(Some(block_hash)) if block_hash == block.hash => { + peer.common_hash = block.hash; + peer.common_number = n; + peer.state = PeerSyncState::Available; + trace!(target:"sync", "Found common ancestor for peer {}: {} ({})", peer_id, block.hash, n); + vec![] + }, + Ok(_) if n > 0 => { + let n = n - 1; + peer.state = PeerSyncState::AncestorSearch(n); + Self::request_ancestry(io, protocol, peer_id, n); + return; + }, + Ok(_) => { // genesis mismatch + io.disable_peer(peer_id); + return; + }, + Err(e) => { + debug!(target:"sync", "Error reading blockchain: {:?}", e); + io.disconnect_peer(peer_id); + return; + } + } + }, + None => { + trace!(target:"sync", "Invalid response when searching for ancestor from {}", peer_id); + io.disconnect_peer(peer_id); + return; + } + } + }, + PeerSyncState::Available => Vec::new(), + } + } else { + vec![] + }; + + // Blocks in the response/drain should be in ascending order. + for block in new_blocks { + let origin = block.origin; + let block = block.block; + if let Some(header) = block.header { + let number = header.number; + let hash = header_hash(&header); + let parent = header.parent_hash; + let result = protocol.chain().import(header, block.body); + match result { + Ok(ImportResult::AlreadyInChain) => { + trace!(target: "sync", "Block already in chain {}: {:?}", number, hash); + self.block_imported(&hash, number); + }, + Ok(ImportResult::AlreadyQueued) => { + trace!(target: "sync", "Block already queued {}: {:?}", number, hash); + self.block_imported(&hash, number); + }, + Ok(ImportResult::Queued) => { + trace!(target: "sync", "Block queued {}: {:?}", number, hash); + self.block_imported(&hash, number); + imported = imported + 1; + }, + Ok(ImportResult::UnknownParent) => { + debug!(target: "sync", "Block with unknown parent {}: {:?}, parent: {:?}", number, hash, parent); + self.restart(io, protocol); + return; + }, + Ok(ImportResult::KnownBad) => { + debug!(target: "sync", "Bad block {}: {:?}", number, hash); + io.disable_peer(origin); //TODO: use persistent ID + self.restart(io, protocol); + return; + } + Err(e) => { + debug!(target: "sync", "Error importing block {}: {:?}: {:?}", number, hash, e); + self.restart(io, protocol); + return; + } + } + } + } + trace!(target: "sync", "Imported {} of {}", imported, count); + self.maintain_sync(io, protocol); + } + + fn maintain_sync(&mut self, io: &mut SyncIo, protocol: &Protocol) { + let peers: Vec = self.peers.keys().map(|p| *p).collect(); + for peer in peers { + self.download_new(io, protocol, peer); + } + } + + fn block_imported(&mut self, hash: &HeaderHash, number: BlockNumber) { + if number > self.best_queued_number { + self.best_queued_number = number; + self.best_queued_hash = *hash; + } + // Update common blocks + for (_, peer) in self.peers.iter_mut() { + if peer.best_number >= number { + peer.common_number = number; + peer.common_hash = *hash; + } + } + } + + pub fn update_chain_info(&mut self, best_header: &Header ) { + let hash = header_hash(&best_header); + self.block_imported(&hash, best_header.number) + } + + pub fn on_block_announce(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, header: &Header) { + let hash = header_hash(&header); + if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + if header.number > peer.best_number { + peer.best_number = header.number; + peer.best_hash = hash; + } + } else { + return; + } + + if !self.is_known_or_already_downloading(protocol, &hash) { + let stale = header.number <= self.best_queued_number; + if stale { + if !self.is_known_or_already_downloading(protocol, &header.parent_hash) { + trace!(target: "sync", "Ignoring unkown stale block announce from {}: {} {:?}", peer_id, hash, header); + } else { + trace!(target: "sync", "Downloading new stale block announced from {}: {} {:?}", peer_id, hash, header); + self.download_stale(io, protocol, peer_id, &hash); + } + } else { + trace!(target: "sync", "Downloading new block announced from {}: {} {:?}", peer_id, hash, header); + self.download_new(io, protocol, peer_id); + } + } else { + trace!(target: "sync", "Known block announce from {}: {}", peer_id, hash); + } + } + + fn is_known_or_already_downloading(&self, protocol: &Protocol, hash: &HeaderHash) -> bool { + self.peers.iter().any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash)) + || protocol.chain().block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown) + } + + pub fn peer_disconnected(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId) { + self.blocks.clear_peer_download(peer_id); + self.peers.remove(&peer_id); + self.maintain_sync(io, protocol); + } + + pub fn restart(&mut self, io: &mut SyncIo, protocol: &Protocol) { + self.blocks.clear(); + let ids: Vec = self.peers.keys().map(|p| *p).collect(); + for id in ids { + self.new_peer(io, protocol, id); + } + match protocol.chain().info() { + Ok(info) => { + self.best_queued_hash = info.best_queued_hash.unwrap_or(info.chain.best_hash); + self.best_queued_number = info.best_queued_number.unwrap_or(info.chain.best_number); + }, + Err(e) => { + debug!(target:"sync", "Error reading blockchain: {:?}", e); + self.best_queued_hash = self.genesis_hash; + self.best_queued_number = 0; + } + } + } + + pub fn clear(&mut self) { + self.blocks.clear(); + self.peers.clear(); + } + + // Download old block. + fn download_stale(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, hash: &HeaderHash) { + if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + match peer.state { + PeerSyncState::Available => { + let request = message::BlockRequest { + id: 0, + fields: self.required_block_attributes.clone(), + from: message::FromBlock::Hash(*hash), + to: None, + direction: message::Direction::Ascending, + max: Some(1), + }; + peer.state = PeerSyncState::DownloadingStale(*hash); + protocol.send_message(io, peer_id, Message::BlockRequest(request)); + }, + _ => (), + } + } + } + + // Issue a request for a peer to download new blocks, if any are available + fn download_new(&mut self, io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId) { + if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { + match peer.state { + PeerSyncState::Available => { + if let Some(range) = self.blocks.needed_blocks(peer_id, MAX_BLOCK_DOWNLOAD, peer.common_number, peer.best_number) { + let request = message::BlockRequest { + id: 0, + fields: self.required_block_attributes.clone(), + from: message::FromBlock::Number(range.start), + to: None, + direction: message::Direction::Ascending, + max: Some((range.end - range.start) as u32), + }; + peer.state = PeerSyncState::DownloadingNew(range.start); + protocol.send_message(io, peer_id, Message::BlockRequest(request)); + } + }, + _ => (), + } + } + } + + fn request_ancestry(io: &mut SyncIo, protocol: &Protocol, peer_id: PeerId, block: BlockNumber) { + let request = message::BlockRequest { + id: 0, + fields: vec![message::BlockAttribute::Header], + from: message::FromBlock::Number(block), + to: None, + direction: message::Direction::Ascending, + max: Some(1), + }; + protocol.send_message(io, peer_id, Message::BlockRequest(request)); + } +} + + + + diff --git a/substrate/network/src/test/mod.rs b/substrate/network/src/test/mod.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/substrate/primitives/src/block.rs b/substrate/primitives/src/block.rs index 8cd077fd78..eb2c7785c2 100644 --- a/substrate/primitives/src/block.rs +++ b/substrate/primitives/src/block.rs @@ -20,24 +20,30 @@ use bytes; use hash::H256; use parachain; +/// Used to refer to a block number. +pub type Number = u64; + /// Hash used to refer to a block hash. pub type HeaderHash = H256; +/// Hash used to refer to a transaction hash. +pub type TransactionHash = H256; + /// Execution log (event) -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub struct Log(#[serde(with="bytes")] pub Vec); /// A relay chain block header. /// /// https://github.com/w3f/polkadot-spec/blob/master/spec.md#header -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct Header { /// Block parent's hash. pub parent_hash: HeaderHash, /// Block number. - pub number: u64, + pub number: Number, /// State root after this transition. pub state_root: H256, /// Parachain activity bitfield @@ -50,7 +56,7 @@ pub struct Header { /// /// Included candidates should be sorted by parachain ID, and without duplicate /// IDs. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct Body { diff --git a/substrate/primitives/src/parachain.rs b/substrate/primitives/src/parachain.rs index ed44134ce2..cecbbb1dbb 100644 --- a/substrate/primitives/src/parachain.rs +++ b/substrate/primitives/src/parachain.rs @@ -98,7 +98,7 @@ pub struct HeadData(#[serde(with="bytes")] pub Vec); pub struct ValidationCode(#[serde(with="bytes")] pub Vec); /// Activitiy bit field -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] pub struct Activity(#[serde(with="bytes")] pub Vec); #[cfg(test)] diff --git a/substrate/rpc/src/chain/mod.rs b/substrate/rpc/src/chain/mod.rs index 86b00795ec..519bdefb4a 100644 --- a/substrate/rpc/src/chain/mod.rs +++ b/substrate/rpc/src/chain/mod.rs @@ -18,6 +18,7 @@ use primitives::block; use client; +use state_machine; mod error; @@ -35,11 +36,12 @@ build_rpc_trait! { } } -impl ChainApi for B where - B: client::Blockchain + Send + Sync + 'static, - B::Error: ::std::error::Error + Send, +impl ChainApi for client::Client where + B: client::backend::Backend + Send + Sync + 'static, + E: state_machine::CodeExecutor + Send + Sync + 'static, + client::error::Error: From<<::State as state_machine::backend::Backend>::Error>, { fn header(&self, hash: block::HeaderHash) -> Result> { - self.header(&hash).chain_err(|| "Blockchain error") + client::Client::header(self, &hash).chain_err(|| "Blockchain error") } } diff --git a/substrate/rpc/src/chain/tests.rs b/substrate/rpc/src/chain/tests.rs index 00208b9598..bf2f3afdac 100644 --- a/substrate/rpc/src/chain/tests.rs +++ b/substrate/rpc/src/chain/tests.rs @@ -14,28 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use primitives::parachain; +use polkadot_executor as executor; +use client; use super::*; -use test_helpers::Blockchain; - #[test] fn should_return_header() { - let state = Blockchain::default(); + let client = client::new_in_mem(executor::executor()).unwrap(); assert_matches!( - ChainApi::header(&state, 0.into()), + ChainApi::header(&client, "11265ce45dd2baaaf071f6df8c5a44f0ed1d85a50e71451ff2d4345e57d12e3a".into()), Ok(Some(ref x)) if x == &block::Header { parent_hash: 0.into(), number: 0, state_root: 0.into(), - parachain_activity: parachain::Activity(vec![0]), + parachain_activity: Default::default(), logs: vec![], } ); assert_matches!( - ChainApi::header(&state, 5.into()), + ChainApi::header(&client, 5.into()), Ok(None) ); } diff --git a/substrate/rpc/src/lib.rs b/substrate/rpc/src/lib.rs index 5061ffb56d..b18f503547 100644 --- a/substrate/rpc/src/lib.rs +++ b/substrate/rpc/src/lib.rs @@ -36,6 +36,3 @@ extern crate assert_matches; pub mod chain; pub mod state; - -#[cfg(test)] -mod test_helpers; diff --git a/substrate/rpc/src/state/mod.rs b/substrate/rpc/src/state/mod.rs index 113fe4849b..12905b7545 100644 --- a/substrate/rpc/src/state/mod.rs +++ b/substrate/rpc/src/state/mod.rs @@ -42,8 +42,9 @@ build_rpc_trait! { } impl StateApi for Client where - B: client::Blockchain + Send + Sync + 'static, + B: client::backend::Backend + Send + Sync + 'static, E: state_machine::CodeExecutor + Send + Sync + 'static, + client::error::Error: From<<::State as state_machine::backend::Backend>::Error>, { fn storage(&self, key: StorageKey, block: block::HeaderHash) -> Result { Ok(self.storage(&block, &key)?) diff --git a/substrate/rpc/src/state/tests.rs b/substrate/rpc/src/state/tests.rs index 20051d4144..b62221adea 100644 --- a/substrate/rpc/src/state/tests.rs +++ b/substrate/rpc/src/state/tests.rs @@ -18,14 +18,15 @@ use super::*; use polkadot_executor as executor; use self::error::{Error, ErrorKind}; -use test_helpers::Blockchain; +use client; #[test] fn should_return_storage() { - let client = Client::new(Blockchain::default(), executor::executor()); + let client = client::new_in_mem(executor::executor()).unwrap(); + let genesis_hash = "11265ce45dd2baaaf071f6df8c5a44f0ed1d85a50e71451ff2d4345e57d12e3a".into(); assert_matches!( - StateApi::storage(&client, StorageKey(vec![10]), 0.into()), + StateApi::storage(&client, StorageKey(vec![10]), genesis_hash), Ok(ref x) if x.0.is_empty() ) } @@ -34,10 +35,11 @@ fn should_return_storage() { #[ignore] // TODO: [ToDr] reenable once we can properly mock the wasm executor env fn should_call_contract() { // TODO [ToDr] Fix test after we are able to mock state. - let client = Client::new(Blockchain::default(), executor::executor()); + let client = client::new_in_mem(executor::executor()).unwrap(); + let genesis_hash = "11265ce45dd2baaaf071f6df8c5a44f0ed1d85a50e71451ff2d4345e57d12e3a".into(); assert_matches!( - StateApi::call(&client, "balanceOf".into(), CallData(vec![1,2,3]), 0.into()), + StateApi::call(&client, "balanceOf".into(), CallData(vec![1,2,3]), genesis_hash), Err(Error(ErrorKind::Client(client::error::ErrorKind::Execution(_)), _)) ) } diff --git a/substrate/state_machine/src/backend.rs b/substrate/state_machine/src/backend.rs index ee6b0bbe80..a97bf2342d 100644 --- a/substrate/state_machine/src/backend.rs +++ b/substrate/state_machine/src/backend.rs @@ -59,7 +59,7 @@ impl error::Error for Void { /// In-memory backend. Fully recomputes tries on each commit but useful for /// tests. -#[derive(Default)] +#[derive(Default, Clone)] pub struct InMemory { inner: MemoryState, // keeps all the state in memory. } @@ -67,7 +67,7 @@ pub struct InMemory { impl Backend for InMemory { type Error = Void; - fn storage(&self, key: &[u8]) -> Result<&[u8], Void> { + fn storage(&self, key: &[u8]) -> Result<&[u8], Self::Error> { Ok(self.inner.storage(key).unwrap_or(&[])) } diff --git a/substrate/state_machine/src/lib.rs b/substrate/state_machine/src/lib.rs index cd7f9291bb..a121cf09c7 100644 --- a/substrate/state_machine/src/lib.rs +++ b/substrate/state_machine/src/lib.rs @@ -43,7 +43,7 @@ pub enum Update { } // in-memory section of the state. -#[derive(Default)] +#[derive(Default, Clone)] struct MemoryState { storage: HashMap, Vec>, } @@ -152,7 +152,7 @@ pub trait Externalities { } /// Code execution engine. -pub trait CodeExecutor: Sized { +pub trait CodeExecutor: Sized + Send + Sync { /// Externalities error type. type Error: Error;