Additional runtime tests for the test-runtime (#69)

* Remove rustc dependency from ed25519 and refactor a little.

* Runtime support provides more extensive test-key functionality.

* Additional APIs for ed25519 stuff.

* Extensive test for test-runtime.

* Fixes for the new test key API.

* Additional convenience for tests

* Take advantage of more convenient API.

* Redo formating.

* Remove old test identities.

* Remove boilerplate, add test.

* Refactor out unneeded code.

* Clean up algo for determining authorities.

* Remove unneeded API.

* Make `to_*` consume

* Only export keyring when testing

* Fix build & warning

* Extract Keyring into separate library.

* Add tests for Keyring and a trait-based API.

* Address grumbles.
This commit is contained in:
Gav Wood
2018-02-12 15:30:38 +01:00
committed by Robert Habermeier
parent 72fa8f3fe2
commit f344e15bf8
38 changed files with 528 additions and 341 deletions
+1
View File
@@ -17,3 +17,4 @@ substrate-runtime-support = { path = "../runtime-support" }
substrate-serializer = { path = "../serializer" }
substrate-state-machine = { path = "../state-machine" }
substrate-test-runtime = { path = "../test-runtime" }
substrate-keyring = { path = "../../substrate/keyring" }
+1 -1
View File
@@ -21,7 +21,7 @@ use error;
use primitives::block;
use blockchain::{self, BlockId};
/// Block insertion transction. Keeps hold if the inseted block state and data.
/// Block insertion transction. Keeps hold if the inserted block state and data.
pub trait BlockImportOperation {
/// Associated state backend type.
type State: state_machine::backend::Backend;
+12
View File
@@ -45,6 +45,18 @@ error_chain! {
description("Blockchain error"),
display("Blockchain: {}", e),
}
/// Invalid state data.
AuthLen {
description("authority count state error"),
display("Current state of blockchain has invalid authority count value"),
}
/// Invalid state data.
Auth(i: u32) {
description("authority value state error"),
display("Current state of blockchain has invalid authority value for index {}", i),
}
}
}
+26 -65
View File
@@ -40,49 +40,23 @@ pub fn construct_genesis_block(storage: &HashMap<Vec<u8>, Vec<u8>>) -> Block {
mod tests {
use super::*;
use codec::{Slicable, Joiner};
use runtime_support::{one, two, Hashable};
use runtime_support::Hashable;
use keyring::Keyring;
use test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
use executor::{NativeExecutionDispatch, NativeExecutor, WasmExecutor, with_native_environment,
error};
use state_machine::{execute, Externalities, OverlayedChanges};
use executor::WasmExecutor;
use state_machine::{execute, OverlayedChanges};
use state_machine::backend::InMemory;
use test_runtime::{self, AccountId, Hash, Block, BlockNumber, Header, Digest, Transaction,
use test_runtime::{self, Hash, Block, BlockNumber, Header, Digest, Transaction,
UncheckedTransaction};
use ed25519::Pair;
use ed25519::{Public, Pair};
/// A null struct which implements `NativeExecutionDispatch` feeding in the hard-coded runtime.
pub struct LocalNativeExecutionDispatch;
impl NativeExecutionDispatch for LocalNativeExecutionDispatch {
fn native_equivalent() -> &'static [u8] {
// WARNING!!! This assumes that the runtime was built *before* the main project. Until we
// get a proper build script, this must be strictly adhered to or things will go wrong.
include_bytes!("../../test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm")
}
fn dispatch(ext: &mut Externalities, method: &str, data: &[u8]) -> error::Result<Vec<u8>> {
with_native_environment(ext, move || test_runtime::apis::dispatch(method, data))?
.ok_or_else(|| error::ErrorKind::MethodNotFound(method.to_owned()).into())
}
}
fn executor() -> NativeExecutor<LocalNativeExecutionDispatch> {
NativeExecutor { _dummy: Default::default() }
}
fn secret_for(who: &AccountId) -> Option<Pair> {
match who {
x if *x == one() => Some(Pair::from_seed(b"12345678901234567890123456789012")),
x if *x == two() => Some("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".into()),
_ => None,
}
}
native_executor_instance!(Executor, test_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;
let transactions = txs.into_iter().map(|tx| {
let signature = secret_for(&tx.from).unwrap()
let signature = Pair::from(Keyring::from_public(Public::from_raw(tx.from)).unwrap())
.sign(&tx.encode());
UncheckedTransaction { tx, signature }
@@ -105,7 +79,7 @@ mod tests {
let ret_data = execute(
backend,
&mut overlay,
&executor(),
&Executor::new(),
"execute_transaction",
&vec![].and(&header).and(tx)
).unwrap();
@@ -115,7 +89,7 @@ mod tests {
let ret_data = execute(
backend,
&mut overlay,
&executor(),
&Executor::new(),
"finalise_block",
&vec![].and(&header)
).unwrap();
@@ -131,8 +105,8 @@ mod tests {
genesis_hash,
hex!("25e5b37074063ab75c889326246640729b40d0c86932edc527bc80db0e04fe5c").into(),
vec![Transaction {
from: one(),
to: two(),
from: Keyring::One.to_raw_public(),
to: Keyring::Two.to_raw_public(),
amount: 69,
nonce: 0,
}]
@@ -142,20 +116,29 @@ mod tests {
#[test]
fn construct_genesis_should_work() {
let mut storage = GenesisConfig::new_simple(
vec![one(), two()], 1000
vec![Keyring::One.to_raw_public(), Keyring::Two.to_raw_public()], 1000
).genesis_map();
let block = construct_genesis_block(&storage);
let genesis_hash = block.header.blake2_256().into();
storage.extend(additional_storage_with_genesis(&block).into_iter());
let mut overlay = OverlayedChanges::default();
let backend = InMemory::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let mut overlay = OverlayedChanges::default();
let _ = execute(
&backend,
&mut overlay,
&executor(),
&Executor::new(),
"execute_block",
&b1data
).unwrap();
let mut overlay = OverlayedChanges::default();
let _ = execute(
&backend,
&mut overlay,
&WasmExecutor,
"execute_block",
&b1data
).unwrap();
@@ -165,42 +148,20 @@ mod tests {
#[should_panic]
fn construct_genesis_with_bad_transaction_should_panic() {
let mut storage = GenesisConfig::new_simple(
vec![one(), two()], 68
vec![Keyring::One.to_raw_public(), Keyring::Two.to_raw_public()], 68
).genesis_map();
let block = construct_genesis_block(&storage);
let genesis_hash = block.header.blake2_256().into();
storage.extend(additional_storage_with_genesis(&block).into_iter());
let mut overlay = OverlayedChanges::default();
let backend = InMemory::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let _ = execute(
&backend,
&mut overlay,
&executor(),
"execute_block",
&b1data
).unwrap();
}
#[test]
fn construct_genesis_should_work_under_wasm() {
let mut storage = GenesisConfig::new_simple(
vec![one(), two()], 1000
).genesis_map();
let block = construct_genesis_block(&storage);
let genesis_hash = block.header.blake2_256().into();
storage.extend(additional_storage_with_genesis(&block).into_iter());
let mut overlay = OverlayedChanges::default();
let backend = InMemory::from(storage);
let (b1data, _b1hash) = block1(genesis_hash, &backend);
let _ = execute(
&backend,
&mut overlay,
&WasmExecutor,
&Executor::new(),
"execute_block",
&b1data
).unwrap();
+50 -3
View File
@@ -22,10 +22,11 @@ extern crate substrate_primitives as primitives;
extern crate substrate_state_machine as state_machine;
extern crate substrate_serializer as ser;
extern crate substrate_codec as codec;
extern crate substrate_executor as executor;
#[cfg(test)] #[macro_use] extern crate substrate_executor as executor;
extern crate ed25519;
#[cfg(test)] extern crate substrate_runtime_support as runtime_support;
#[cfg(test)] extern crate substrate_test_runtime as test_runtime;
#[cfg(test)] extern crate substrate_keyring as keyring;
extern crate triehash;
extern crate parking_lot;
@@ -42,8 +43,9 @@ pub mod genesis;
pub use blockchain::Info as ChainInfo;
pub use blockchain::BlockId;
use primitives::block;
use primitives::{block, AuthorityId};
use primitives::storage::{StorageKey, StorageData};
use codec::{KeyedVec, Slicable};
use blockchain::Backend as BlockchainBackend;
use backend::BlockImportOperation;
@@ -162,7 +164,18 @@ impl<B, E> Client<B, E> where
/// Get the code at a given block.
pub fn code_at(&self, id: &BlockId) -> error::Result<Vec<u8>> {
self.storage(id, &StorageKey(b":code:".to_vec())).map(|data| data.0)
self.storage(id, &StorageKey(b":code".to_vec())).map(|data| data.0)
}
/// Get the current set of authorities from storage.
pub fn authorities_at(&self, id: &BlockId) -> error::Result<Vec<AuthorityId>> {
let state = self.state_at(id)?;
(0..u32::decode(&mut state.storage(b":auth:len")?).ok_or(error::ErrorKind::AuthLen)?)
.map(|i| state.storage(&i.to_keyed_vec(b":auth:"))
.map_err(|_| error::ErrorKind::Backend)
.and_then(|mut s| AuthorityId::decode(&mut s).ok_or(error::ErrorKind::Auth(i)))
.map_err(Into::into)
).collect()
}
/// Execute a call to a contract on top of state in a block of given hash.
@@ -235,3 +248,37 @@ impl<B, E> Client<B, E> where
self.backend.blockchain().body(*id)
}
}
#[cfg(test)]
mod tests {
use super::*;
use codec::Slicable;
use keyring::Keyring;
use test_runtime::genesismap::{GenesisConfig, additional_storage_with_genesis};
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"));
#[test]
fn authorities_call_works() {
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();
assert_eq!(client.authorities_at(&BlockId::Number(0)).unwrap(), vec![
Keyring::Alice.to_raw_public(),
Keyring::Bob.to_raw_public(),
Keyring::Charlie.to_raw_public()
]);
}
}