diff --git a/Cargo.lock b/Cargo.lock index 6a67beb3dfd6e..5b48ad157ada8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -825,7 +825,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "8.0.2" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -837,7 +837,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc.git)", @@ -850,7 +850,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc.git)", "jsonrpc-pubsub 8.0.1 (git+https://github.com/paritytech/jsonrpc.git)", @@ -860,7 +860,7 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc.git)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" version = "8.0.1" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -883,7 +883,7 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" version = "8.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git#9cfa451b0534281d83f7564bf41fda465a6e18c8" +source = "git+https://github.com/paritytech/jsonrpc.git#0fd13be062625c6d4c89859c8686d4da3bbb552c" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.2 (git+https://github.com/paritytech/jsonrpc.git)", @@ -1794,7 +1794,7 @@ dependencies = [ "substrate-runtime-io 0.1.0", "substrate-runtime-support 0.1.0", "substrate-state-machine 0.1.0", - "substrate-test-runtime 0.1.0", + "substrate-test-client 0.1.0", "triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1868,13 +1868,12 @@ dependencies = [ "substrate-bft 0.1.0", "substrate-client 0.1.0", "substrate-codec 0.1.0", - "substrate-executor 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-support 0.1.0", "substrate-serializer 0.1.0", "substrate-state-machine 0.1.0", - "substrate-test-runtime 0.1.0", + "substrate-test-client 0.1.0", ] [[package]] @@ -1910,8 +1909,8 @@ dependencies = [ "substrate-client 0.1.0", "substrate-executor 0.1.0", "substrate-primitives 0.1.0", - "substrate-runtime-support 0.1.0", "substrate-state-machine 0.1.0", + "substrate-test-client 0.1.0", "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2141,6 +2140,20 @@ dependencies = [ "triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "substrate-test-client" +version = "0.1.0" +dependencies = [ + "substrate-bft 0.1.0", + "substrate-client 0.1.0", + "substrate-codec 0.1.0", + "substrate-executor 0.1.0", + "substrate-keyring 0.1.0", + "substrate-primitives 0.1.0", + "substrate-runtime-support 0.1.0", + "substrate-test-runtime 0.1.0", +] + [[package]] name = "substrate-test-runtime" version = "0.1.0" diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 5d0f1d45752a3..0438a9afaca90 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -21,4 +21,4 @@ substrate-state-machine = { path = "../state-machine" } substrate-keyring = { path = "../../substrate/keyring" } [dev-dependencies] -substrate-test-runtime = { path = "../test-runtime" } +substrate-test-client = { path = "../test-client" } diff --git a/substrate/client/src/blockchain.rs b/substrate/client/src/blockchain.rs index 095cbe3cbee8a..69a7a2a18a422 100644 --- a/substrate/client/src/blockchain.rs +++ b/substrate/client/src/blockchain.rs @@ -20,7 +20,6 @@ use primitives::block::{self, Id as BlockId}; use primitives; use error::Result; - /// Blockchain database backend. Does not perform any validation. pub trait Backend: Send + Sync { /// Get block header. Returns `None` if block is not found. diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index 0eba8d9fa56bd..6686da42e2a7b 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -452,62 +452,15 @@ mod tests { use super::*; use codec::Slicable; use keyring::Keyring; - use {primitives, genesis}; use primitives::block::Extrinsic as PrimitiveExtrinsic; - use test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; - use test_runtime::{UncheckedTransaction, Transaction}; - use test_runtime; - - native_executor_instance!(Executor, test_runtime::api::dispatch, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); - - fn genesis_config() -> GenesisConfig { - GenesisConfig::new_simple(vec![ - Keyring::Alice.to_raw_public(), - Keyring::Bob.to_raw_public(), - Keyring::Charlie.to_raw_public() - ], 1000) - } - - fn prepare_genesis() -> (primitives::block::Header, Vec<(Vec, Vec)>) { - let mut storage = genesis_config().genesis_map(); - let block = genesis::construct_genesis_block(&storage); - storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) - } - - // since we are in the client module we can create falsely justified - // headers. - // TODO: remove this in favor of custom verification pipelines for the - // client - fn justify(header: &block::Header) -> bft::UncheckedJustification { - let hash = header.blake2_256().into(); - let authorities = vec![ - Keyring::Alice.into(), - Keyring::Bob.into(), - Keyring::Charlie.into(), - ]; - - bft::UncheckedJustification { - digest: hash, - signatures: authorities.iter().map(|key| { - let msg = bft::sign_message( - bft::generic::Vote::Commit(1, hash).into(), - key, - header.parent_hash - ); - - match msg { - bft::generic::LocalizedMessage::Vote(vote) => vote.signature, - _ => panic!("signing vote leads to signed vote"), - } - }).collect(), - round_number: 1, - } - } + use test_client::{self, TestClient}; + use test_client::client::BlockOrigin; + use test_client::runtime as test_runtime; + use test_client::runtime::{UncheckedTransaction, Transaction}; #[test] fn client_initialises_from_genesis_ok() { - let client = new_in_mem(Executor::new(), prepare_genesis).unwrap(); + let client = test_client::new(); let genesis_hash = client.block_hash(0).unwrap().unwrap(); assert_eq!(client.using_environment(|| test_runtime::system::latest_block_hash()).unwrap(), genesis_hash); @@ -517,15 +470,7 @@ mod tests { #[test] fn authorities_call_works() { - let genesis_config = genesis_config(); - - let prepare_genesis = || { - let mut storage = genesis_config.genesis_map(); - let block = genesis::construct_genesis_block(&storage); - storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) - }; - let client = new_in_mem(Executor::new(), prepare_genesis).unwrap(); + let client = test_client::new(); assert_eq!(client.info().unwrap().chain.best_number, 0); assert_eq!(client.authorities_at(&BlockId::Number(0)).unwrap(), vec![ @@ -537,22 +482,11 @@ mod tests { #[test] fn block_builder_works_with_no_transactions() { - let genesis_config = genesis_config(); - - let prepare_genesis = || { - let mut storage = genesis_config.genesis_map(); - let block = genesis::construct_genesis_block(&storage); - storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) - }; - let client = new_in_mem(Executor::new(), prepare_genesis).unwrap(); + let client = test_client::new(); let builder = client.new_block().unwrap(); - let block = builder.bake().unwrap(); - let justification = justify(&block.header); - let justified = client.check_justification(block.header, justification).unwrap(); - client.import_block(BlockOrigin::Own, justified, Some(block.transactions)).unwrap(); + client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap(); assert_eq!(client.info().unwrap().chain.best_number, 1); assert_eq!(client.using_environment(|| test_runtime::system::latest_block_hash()).unwrap(), client.block_hash(1).unwrap().unwrap()); @@ -570,19 +504,7 @@ mod tests { #[test] fn block_builder_works_with_transactions() { - let genesis_config = GenesisConfig::new_simple(vec![ - Keyring::Alice.to_raw_public(), - Keyring::Bob.to_raw_public(), - Keyring::Charlie.to_raw_public() - ], 1000); - - let prepare_genesis = || { - let mut storage = genesis_config.genesis_map(); - let block = genesis::construct_genesis_block(&storage); - storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) - }; - let client = new_in_mem(Executor::new(), prepare_genesis).unwrap(); + let client = test_client::new(); let mut builder = client.new_block().unwrap(); @@ -592,11 +514,8 @@ mod tests { amount: 42, nonce: 0 }.signed()).unwrap(); - let block = builder.bake().unwrap(); - let justification = justify(&block.header); - let justified = client.check_justification(block.header, justification).unwrap(); - client.import_block(BlockOrigin::Own, justified, Some(block.transactions)).unwrap(); + client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap(); assert_eq!(client.info().unwrap().chain.best_number, 1); assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap()); diff --git a/substrate/client/src/genesis.rs b/substrate/client/src/genesis.rs index 12efe91ddc82e..c1cc82f90f3ed 100644 --- a/substrate/client/src/genesis.rs +++ b/substrate/client/src/genesis.rs @@ -42,15 +42,16 @@ mod tests { use codec::{Slicable, Joiner}; use runtime_support::Hashable; use keyring::Keyring; - use test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; use executor::WasmExecutor; use state_machine::{execute, OverlayedChanges}; use state_machine::backend::InMemory; - use test_runtime::{self, Hash, Block, BlockNumber, Header, Digest, Transaction, + use test_client; + use test_client::runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; + use test_client::runtime::{Hash, Block, BlockNumber, Header, Digest, Transaction, UncheckedTransaction}; use ed25519::{Public, Pair}; - native_executor_instance!(Executor, test_runtime::api::dispatch, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); + native_executor_instance!(Executor, test_client::runtime::api::dispatch, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); fn construct_block(backend: &InMemory, number: BlockNumber, parent_hash: Hash, state_root: Hash, txs: Vec) -> (Vec, Hash) { use triehash::ordered_trie_root; diff --git a/substrate/client/src/lib.rs b/substrate/client/src/lib.rs index 8690b19f2d3f2..7ef6b65d94314 100644 --- a/substrate/client/src/lib.rs +++ b/substrate/client/src/lib.rs @@ -19,22 +19,23 @@ #![warn(missing_docs)] extern crate substrate_bft as bft; -extern crate substrate_runtime_support as runtime_support; -extern crate substrate_runtime_io as runtime_io; +extern crate substrate_codec as codec; extern crate substrate_primitives as primitives; +extern crate substrate_runtime_io as runtime_io; +extern crate substrate_runtime_support as runtime_support; extern crate substrate_state_machine as state_machine; -extern crate substrate_codec as codec; -#[cfg(test)] #[macro_use] extern crate substrate_executor as executor; -extern crate ed25519; -#[cfg(test)] extern crate substrate_test_runtime as test_runtime; #[cfg(test)] extern crate substrate_keyring as keyring; +#[cfg(test)] extern crate substrate_test_client as test_client; -extern crate triehash; -extern crate parking_lot; +extern crate ed25519; extern crate futures; -#[cfg(test)] #[macro_use] extern crate hex_literal; +extern crate parking_lot; +extern crate triehash; + #[macro_use] extern crate error_chain; #[macro_use] extern crate log; +#[cfg(test)] #[macro_use] extern crate substrate_executor as executor; +#[cfg(test)] #[macro_use] extern crate hex_literal; pub mod error; pub mod blockchain; @@ -44,6 +45,10 @@ pub mod genesis; pub mod block_builder; mod client; -pub use client::{Client, ClientInfo, CallResult, ImportResult, ChainHead, - BlockStatus, BlockOrigin, new_in_mem, BlockchainEventStream, BlockchainEvents}; +pub use client::{ + new_in_mem, + BlockStatus, BlockOrigin, BlockchainEventStream, BlockchainEvents, + Client, ClientInfo, CallResult, ChainHead, + ImportResult, +}; pub use blockchain::Info as ChainInfo; diff --git a/substrate/network/Cargo.toml b/substrate/network/Cargo.toml index 5b1fe410d6c56..6a540d4b76a66 100644 --- a/substrate/network/Cargo.toml +++ b/substrate/network/Cargo.toml @@ -29,9 +29,7 @@ substrate-runtime-support = { path = "../../substrate/runtime-support" } substrate-bft = { path = "../../substrate/bft" } [dev-dependencies] -substrate-test-runtime = { path = "../test-runtime" } -substrate-executor = { path = "../../substrate/executor" } -substrate-keyring = { path = "../../substrate/keyring" } -substrate-codec = { path = "../../substrate/codec" } -substrate-bft = { path = "../bft" } env_logger = "0.4" +substrate-codec = { path = "../../substrate/codec" } +substrate-keyring = { path = "../../substrate/keyring" } +substrate-test-client = { path = "../../substrate/test-client" } diff --git a/substrate/network/src/lib.rs b/substrate/network/src/lib.rs index 6ccfb965930f2..3cc9d994eee91 100644 --- a/substrate/network/src/lib.rs +++ b/substrate/network/src/lib.rs @@ -40,11 +40,9 @@ extern crate ed25519; #[macro_use] extern crate error_chain; #[cfg(test)] extern crate env_logger; -#[cfg(test)] extern crate substrate_test_runtime as test_runtime; -#[cfg(test)] extern crate substrate_keyring as keyring; -#[cfg(test)] #[macro_use] extern crate substrate_executor as executor; #[cfg(test)] extern crate substrate_codec as codec; -#[cfg(test)] extern crate substrate_bft as bft; +#[cfg(test)] extern crate substrate_keyring as keyring; +#[cfg(test)] extern crate substrate_test_client as test_client; mod service; mod sync; diff --git a/substrate/network/src/test/mod.rs b/substrate/network/src/test/mod.rs index afa6d82e32f0b..36c4ec34d5cb1 100644 --- a/substrate/network/src/test/mod.rs +++ b/substrate/network/src/test/mod.rs @@ -18,25 +18,21 @@ mod sync; use std::collections::{VecDeque, HashSet, HashMap}; use std::sync::Arc; + use parking_lot::RwLock; -use client::{self, genesis, BlockOrigin}; +use client; use client::block_builder::BlockBuilder; use primitives::block::{Id as BlockId, ExtrinsicHash}; use primitives; -use executor; use io::SyncIo; use protocol::Protocol; use config::ProtocolConfig; use service::TransactionPool; use network::{PeerId, SessionInfo, Error as NetworkError}; -use test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; use runtime_support::Hashable; -use test_runtime; use keyring::Keyring; use codec::Slicable; -use bft; - -native_executor_instance!(Executor, test_runtime::api::dispatch, include_bytes!("../../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); +use test_client::{self, TestClient}; pub struct TestIo<'p> { pub queue: &'p RwLock>, @@ -103,7 +99,7 @@ pub struct TestPacket { } pub struct Peer { - client: Arc>>, + client: Arc>, pub sync: Protocol, pub queue: RwLock>, } @@ -161,37 +157,13 @@ impl Peer { fn flush(&self) { } - fn justify(header: &primitives::block::Header) -> bft::UncheckedJustification { - let hash = header.blake2_256().into(); - let authorities = vec![ Keyring::Alice.into() ]; - - bft::UncheckedJustification { - digest: hash, - signatures: authorities.iter().map(|key| { - let msg = bft::sign_message( - bft::generic::Vote::Commit(1, hash).into(), - key, - header.parent_hash - ); - - match msg { - bft::generic::LocalizedMessage::Vote(vote) => vote.signature, - _ => panic!("signing vote leads to signed vote"), - } - }).collect(), - round_number: 1, - } - } - - fn generate_blocks(&self, count: usize, mut edit_block: F) where F: FnMut(&mut BlockBuilder>) { + fn generate_blocks(&self, count: usize, mut edit_block: F) where F: FnMut(&mut BlockBuilder) { for _ in 0 .. count { let mut builder = self.client.new_block().unwrap(); edit_block(&mut builder); let block = builder.bake().unwrap(); trace!("Generating {}, (#{})", primitives::block::HeaderHash::from(block.header.blake2_256()), block.header.number); - let justification = Self::justify(&block.header); - let justified = self.client.check_justification(block.header, justification).unwrap(); - self.client.import_block(BlockOrigin::File, justified, Some(block.transactions)).unwrap(); + self.client.justify_and_import(client::BlockOrigin::File, block).unwrap(); } } @@ -199,14 +171,14 @@ impl Peer { let mut nonce = 0; if with_tx { self.generate_blocks(count, |builder| { - let tx = test_runtime::Transaction { + let tx = test_client::runtime::Transaction { from: Keyring::Alice.to_raw_public(), to: Keyring::Alice.to_raw_public(), amount: 1, nonce: nonce, }; let signature = Keyring::from_raw_public(tx.from.clone()).unwrap().sign(&tx.encode()); - let tx = primitives::block::Extrinsic::decode(&mut test_runtime::UncheckedTransaction { signature, tx: tx }.encode().as_ref()).unwrap(); + let tx = primitives::block::Extrinsic::decode(&mut test_client::runtime::UncheckedTransaction { signature, tx: tx }.encode().as_ref()).unwrap(); builder.push(tx).unwrap(); nonce = nonce + 1; }); @@ -235,19 +207,6 @@ pub struct TestNet { } impl TestNet { - fn genesis_config() -> GenesisConfig { - GenesisConfig::new_simple(vec![ - Keyring::Alice.to_raw_public(), - ], 1000) - } - - fn prepare_genesis() -> (primitives::block::Header, Vec<(Vec, Vec)>) { - let mut storage = Self::genesis_config().genesis_map(); - let block = genesis::construct_genesis_block(&storage); - storage.extend(additional_storage_with_genesis(&block)); - (primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect()) - } - pub fn new(n: usize) -> Self { Self::new_with_config(n, ProtocolConfig::default()) } @@ -260,7 +219,7 @@ impl TestNet { }; for _ in 0..n { - let client = Arc::new(client::new_in_mem(Executor::new(), Self::prepare_genesis).unwrap()); + let client = Arc::new(test_client::new()); let tx_pool = Arc::new(EmptyTransactionPool); let sync = Protocol::new(config.clone(), client.clone(), tx_pool).unwrap(); net.peers.push(Arc::new(Peer { diff --git a/substrate/rpc/Cargo.toml b/substrate/rpc/Cargo.toml index 7aaea95700bb5..d2e2547f4c331 100644 --- a/substrate/rpc/Cargo.toml +++ b/substrate/rpc/Cargo.toml @@ -18,5 +18,4 @@ tokio-core = "0.1.12" [dev-dependencies] assert_matches = "1.1" -substrate-executor = { path = "../executor" } -substrate-runtime-support = { path = "../runtime-support" } +substrate-test-client = { path = "../test-client" } diff --git a/substrate/rpc/src/chain/tests.rs b/substrate/rpc/src/chain/tests.rs index b44f107fac1cd..6d44ba7a3f708 100644 --- a/substrate/rpc/src/chain/tests.rs +++ b/substrate/rpc/src/chain/tests.rs @@ -14,42 +14,64 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use substrate_executor as executor; -use client; -use runtime_support::Hashable; use super::*; +use jsonrpc_macros::pubsub; +use client::BlockOrigin; +use test_client::{self, TestClient}; #[test] fn should_return_header() { - let test_genesis_block = block::Header { - parent_hash: 0.into(), - number: 0, - state_root: 0.into(), - extrinsics_root: Default::default(), - digest: Default::default(), - }; - let core = ::tokio_core::reactor::Core::new().unwrap(); let remote = core.remote(); let client = Chain { - client: Arc::new(client::new_in_mem(executor::WasmExecutor, || (test_genesis_block.clone(), vec![])).unwrap()), + client: Arc::new(test_client::new()), subscriptions: Subscriptions::new(remote), }; assert_matches!( - ChainApi::header(&client, test_genesis_block.blake2_256().into()), + client.header(client.client.genesis_hash()), Ok(Some(ref x)) if x == &block::Header { parent_hash: 0.into(), number: 0, - state_root: 0.into(), - extrinsics_root: Default::default(), + state_root: "6da331d07a82d99f4debaafb0110a2e36244ed34162f9a7f6312a23fd52989ed".into(), + extrinsics_root: "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".into(), digest: Default::default(), } ); assert_matches!( - ChainApi::header(&client, 5.into()), + client.header(5.into()), Ok(None) ); } + +#[test] +fn should_notify_about_latest_block() { + let mut core = ::tokio_core::reactor::Core::new().unwrap(); + let remote = core.remote(); + let (subscriber, id, transport) = pubsub::Subscriber::new_test("test"); + + { + let api = Chain { + client: Arc::new(test_client::new()), + subscriptions: Subscriptions::new(remote), + }; + + api.subscribe_new_head(Default::default(), subscriber); + + // assert id assigned + assert_eq!(core.run(id), Ok(Ok(SubscriptionId::Number(0)))); + + let builder = api.client.new_block().unwrap(); + api.client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap(); + } + + // assert notification send to transport + let (notification, next) = core.run(transport.into_future()).unwrap(); + assert_eq!(notification, Some( + r#"{"jsonrpc":"2.0","method":"test","params":{"result":{"digest":{"logs":[]},"extrinsicsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","number":1,"parentHash":"0x4c4ab196ed07bbd5b8c901ae5092d9d3990cbb4d44421af8e988af7d3c2a4226","stateRoot":"0x75b634da2a0d272e8a5145ab704406d3b50676c7739f977f2ccb2d0e5a0cdbd0"},"subscription":0}}"#.to_owned() + )); + // no more notifications on this channel + assert_eq!(core.run(next.into_future()).unwrap().0, None); +} diff --git a/substrate/rpc/src/lib.rs b/substrate/rpc/src/lib.rs index ddc8accf94b8f..54f8739e33f2e 100644 --- a/substrate/rpc/src/lib.rs +++ b/substrate/rpc/src/lib.rs @@ -33,13 +33,11 @@ extern crate jsonrpc_macros; #[macro_use] extern crate log; -#[cfg(test)] -extern crate substrate_executor; #[cfg(test)] #[macro_use] extern crate assert_matches; #[cfg(test)] -extern crate substrate_runtime_support as runtime_support; +extern crate substrate_test_client as test_client; mod subscriptions; diff --git a/substrate/rpc/src/state/tests.rs b/substrate/rpc/src/state/tests.rs index 3cbf75693aecd..1b98711ea5e99 100644 --- a/substrate/rpc/src/state/tests.rs +++ b/substrate/rpc/src/state/tests.rs @@ -15,23 +15,13 @@ // along with Substrate. If not, see . use super::*; -use substrate_executor as executor; use self::error::{Error, ErrorKind}; -use runtime_support::Hashable; -use client; +use test_client::{self, TestClient}; #[test] fn should_return_storage() { - let test_genesis_block = block::Header { - parent_hash: 0.into(), - number: 0, - state_root: 0.into(), - extrinsics_root: Default::default(), - digest: Default::default(), - }; - - let client = Arc::new(client::new_in_mem(executor::WasmExecutor, || (test_genesis_block.clone(), vec![])).unwrap()); - let genesis_hash = test_genesis_block.blake2_256().into(); + let client = Arc::new(test_client::new()); + let genesis_hash = client.genesis_hash(); assert_matches!( StateApi::storage_at(&client, StorageKey(vec![10]), genesis_hash), @@ -40,19 +30,9 @@ fn should_return_storage() { } #[test] -#[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 test_genesis_block = block::Header { - parent_hash: 0.into(), - number: 0, - state_root: 0.into(), - extrinsics_root: Default::default(), - digest: Default::default(), - }; - - let client = Arc::new(client::new_in_mem(executor::WasmExecutor, || (test_genesis_block.clone(), vec![])).unwrap()); - let genesis_hash = test_genesis_block.blake2_256().into(); + let client = Arc::new(test_client::new()); + let genesis_hash = client.genesis_hash(); assert_matches!( StateApi::call_at(&client, "balanceOf".into(), vec![1,2,3], genesis_hash), diff --git a/substrate/test-client/Cargo.toml b/substrate/test-client/Cargo.toml new file mode 100644 index 0000000000000..e12149fc2c547 --- /dev/null +++ b/substrate/test-client/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "substrate-test-client" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +substrate-bft = { path = "../bft" } +substrate-client = { path = "../client" } +substrate-codec = { path = "../codec" } +substrate-executor = { path = "../executor" } +substrate-keyring = { path = "../../substrate/keyring" } +substrate-primitives = { path = "../primitives" } +substrate-runtime-support = { path = "../runtime-support" } +substrate-test-runtime = { path = "../test-runtime" } diff --git a/substrate/test-client/src/client_ext.rs b/substrate/test-client/src/client_ext.rs new file mode 100644 index 0000000000000..3af87c4db4fcc --- /dev/null +++ b/substrate/test-client/src/client_ext.rs @@ -0,0 +1,108 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Client extension for tests. + +use codec::Slicable; +use client::{self, Client}; +use keyring::Keyring; +use runtime_support::Hashable; +use runtime::genesismap::{GenesisConfig, additional_storage_with_genesis}; +use primitives::block; +use bft; +use {Backend, Executor, NativeExecutor}; + +/// Extension trait for a test client. +pub trait TestClient { + /// Crates new client instance for tests. + fn new_for_tests() -> Self; + + /// Justify and import block to the chain. + fn justify_and_import(&self, origin: client::BlockOrigin, block: block::Block) -> client::error::Result<()>; + + /// Returns hash of the genesis block. + fn genesis_hash(&self) -> block::HeaderHash; +} + +impl TestClient for Client { + fn new_for_tests() -> Self { + client::new_in_mem(NativeExecutor::new(), prepare_genesis).unwrap() + } + + fn justify_and_import(&self, origin: client::BlockOrigin, block: block::Block) -> client::error::Result<()> { + let justification = fake_justify(&block.header); + let justified = self.check_justification(block.header, justification)?; + self.import_block(origin, justified, Some(block.transactions))?; + + Ok(()) + } + + fn genesis_hash(&self) -> block::HeaderHash { + self.block_hash(0).unwrap().unwrap() + } +} + +/// Prepare fake justification for the header. +/// +/// since we are in the client module we can create falsely justified +/// headers. +/// TODO: remove this in favor of custom verification pipelines for the +/// client +fn fake_justify(header: &block::Header) -> bft::UncheckedJustification { + let hash = header.blake2_256().into(); + let authorities = vec![ + Keyring::Alice.into(), + Keyring::Bob.into(), + Keyring::Charlie.into(), + ]; + + bft::UncheckedJustification { + digest: hash, + signatures: authorities.iter().map(|key| { + let msg = bft::sign_message( + bft::generic::Vote::Commit(1, hash).into(), + key, + header.parent_hash + ); + + match msg { + bft::generic::LocalizedMessage::Vote(vote) => vote.signature, + _ => panic!("signing vote leads to signed vote"), + } + }).collect(), + round_number: 1, + } +} + +fn genesis_config() -> GenesisConfig { + GenesisConfig::new_simple(vec![ + Keyring::Alice.to_raw_public(), + Keyring::Bob.to_raw_public(), + Keyring::Charlie.to_raw_public() + ], 1000) +} + +fn prepare_genesis() -> (block::Header, Vec<(Vec, Vec)>) { + let mut storage = genesis_config().genesis_map(); + let block = client::genesis::construct_genesis_block(&storage); + storage.extend(additional_storage_with_genesis(&block)); + + ( + block::Header::decode(&mut block.header.encode().as_ref()) + .expect("to_vec() always gives a valid serialisation; qed"), + storage.into_iter().collect() + ) +} diff --git a/substrate/test-client/src/lib.rs b/substrate/test-client/src/lib.rs new file mode 100644 index 0000000000000..123a8a6398699 --- /dev/null +++ b/substrate/test-client/src/lib.rs @@ -0,0 +1,54 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! Client testing utilities. + +#![warn(missing_docs)] + +extern crate substrate_bft as bft; +extern crate substrate_codec as codec; +extern crate substrate_keyring as keyring; +extern crate substrate_primitives as primitives; +extern crate substrate_runtime_support as runtime_support; +#[macro_use] extern crate substrate_executor as executor; + +pub extern crate substrate_test_runtime as runtime; +pub extern crate substrate_client as client; + +mod client_ext; + +pub use client_ext::TestClient; + +mod native_executor { + #![allow(missing_docs)] + use super::runtime; + + native_executor_instance!(pub NativeExecutor, runtime::api::dispatch, include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")); +} + +/// Native executor used for tests. +pub use self::native_executor::NativeExecutor; + +/// Test client database backend. +pub type Backend = client::in_mem::Backend; + +/// Test client executor. +pub type Executor = executor::NativeExecutor; + +/// Creates new client instance used for tests. +pub fn new() -> client::Client { + TestClient::new_for_tests() +}