mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 17:31:05 +00:00
Substrate test client crate & chain subscription test (#139)
* Test client used in RPC tests. * Use test-client for network tests. * Expose BlockOrigin and clean up the API.
This commit is contained in:
committed by
Robert Habermeier
parent
101549238e
commit
f116f67382
Generated
+23
-10
@@ -834,7 +834,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)",
|
||||
@@ -846,7 +846,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)",
|
||||
@@ -859,7 +859,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)",
|
||||
@@ -869,7 +869,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)",
|
||||
@@ -879,7 +879,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)",
|
||||
@@ -892,7 +892,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)",
|
||||
@@ -1810,7 +1810,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)",
|
||||
]
|
||||
|
||||
@@ -1884,13 +1884,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]]
|
||||
@@ -1926,8 +1925,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)",
|
||||
]
|
||||
|
||||
@@ -2157,6 +2156,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"
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -447,62 +447,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<u8>, Vec<u8>)>) {
|
||||
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);
|
||||
@@ -512,15 +465,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![
|
||||
@@ -532,22 +477,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());
|
||||
@@ -565,19 +499,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();
|
||||
|
||||
@@ -587,11 +509,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());
|
||||
|
||||
@@ -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<Transaction>) -> (Vec<u8>, Hash) {
|
||||
use triehash::ordered_trie_root;
|
||||
|
||||
@@ -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_primitives as primitives;
|
||||
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;
|
||||
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;
|
||||
#[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;
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<VecDeque<TestPacket>>,
|
||||
@@ -103,7 +99,7 @@ pub struct TestPacket {
|
||||
}
|
||||
|
||||
pub struct Peer {
|
||||
client: Arc<client::Client<client::in_mem::Backend, executor::NativeExecutor<Executor>>>,
|
||||
client: Arc<client::Client<test_client::Backend, test_client::Executor>>,
|
||||
pub sync: Protocol,
|
||||
pub queue: RwLock<VecDeque<TestPacket>>,
|
||||
}
|
||||
@@ -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<F>(&self, count: usize, mut edit_block: F) where F: FnMut(&mut BlockBuilder<client::in_mem::Backend, executor::NativeExecutor<Executor>>) {
|
||||
fn generate_blocks<F>(&self, count: usize, mut edit_block: F) where F: FnMut(&mut BlockBuilder<test_client::Backend, test_client::Executor>) {
|
||||
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<u8>, Vec<u8>)>) {
|
||||
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 {
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -14,42 +14,64 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -15,23 +15,13 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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),
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "substrate-test-client"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[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" }
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Backend, Executor> {
|
||||
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<u8>, Vec<u8>)>) {
|
||||
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()
|
||||
)
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<NativeExecutor>;
|
||||
|
||||
/// Creates new client instance used for tests.
|
||||
pub fn new() -> client::Client<Backend, Executor> {
|
||||
TestClient::new_for_tests()
|
||||
}
|
||||
Reference in New Issue
Block a user