diff --git a/substrate/.gitlab-ci.yml b/substrate/.gitlab-ci.yml index f29e1b0dc8..b82a3f1392 100644 --- a/substrate/.gitlab-ci.yml +++ b/substrate/.gitlab-ci.yml @@ -96,6 +96,34 @@ test-linux-stable: &test - time cargo test --all --release --verbose --locked - sccache -s +test-linux-stable-int: &test + stage: test + variables: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: -Cdebug-assertions=y + TARGET: native + tags: + - linux-docker + only: + - tags + - master + - schedules + - web + - /^[0-9]+$/ + except: + variables: + - $DEPLOY_TAG + before_script: + - sccache -s + - ./scripts/build.sh + script: + - time RUST_LOG=sync=trace,consensus=trace,client=trace,state-db=trace,db=trace,forks=trace,state_db=trace,storage_cache=trace cargo test -p node-cli --release --verbose --locked -- --ignored --test-threads=1 + - sccache -s + allow_failure: true + + check-web-wasm: stage: test <<: *compiler_info diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index da3ae1f4dc..0246844271 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -2152,6 +2152,7 @@ dependencies = [ "substrate-cli 2.0.0", "substrate-client 2.0.0", "substrate-consensus-aura 2.0.0", + "substrate-consensus-common 2.0.0", "substrate-finality-grandpa 2.0.0", "substrate-inherents 2.0.0", "substrate-keyring 2.0.0", diff --git a/substrate/core/consensus/aura/src/lib.rs b/substrate/core/consensus/aura/src/lib.rs index 901d8b6f35..6f73c6ed65 100644 --- a/substrate/core/consensus/aura/src/lib.rs +++ b/substrate/core/consensus/aura/src/lib.rs @@ -69,9 +69,9 @@ use slots::{CheckedHeader, SlotWorker, SlotInfo, SlotCompatible, slot_now, check pub use aura_primitives::*; pub use consensus_common::{SyncOracle, ExtraVerification}; +pub use digest::CompatibleDigestItem; mod digest; -use digest::CompatibleDigestItem; type AuthorityId

=

::Public; diff --git a/substrate/core/service/test/src/lib.rs b/substrate/core/service/test/src/lib.rs index 9b73cfa14c..7a6d530030 100644 --- a/substrate/core/service/test/src/lib.rs +++ b/substrate/core/service/test/src/lib.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; use log::info; use futures::{Future, Stream}; use tempdir::TempDir; -use tokio::runtime::Runtime; +use tokio::{runtime::Runtime, prelude::FutureExt}; use tokio::timer::Interval; use service::{ ServiceFactory, @@ -39,6 +39,9 @@ use network::config::{NetworkConfiguration, NodeKeyConfig, Secret, NonReservedPe use sr_primitives::generic::BlockId; use consensus::{ImportBlock, BlockImport}; +/// Maximum duration of single wait call. +const MAX_WAIT_TIME: Duration = Duration::from_secs(60 * 3); + struct TestNet { runtime: Runtime, authority_nodes: Vec<(u32, Arc, Multiaddr)>, @@ -52,14 +55,22 @@ struct TestNet { impl TestNet { pub fn run_until_all_full bool + 'static>(&mut self, predicate: P) { let full_nodes = self.full_nodes.clone(); - let interval = Interval::new_interval(Duration::from_millis(100)).map_err(|_| ()).for_each(move |_| { - if full_nodes.iter().all(|&(ref id, ref service, _)| predicate(*id, service)) { - Err(()) - } else { - Ok(()) - } - }); - self.runtime.block_on(interval).ok(); + let interval = Interval::new_interval(Duration::from_millis(100)) + .map_err(|_| ()) + .for_each(move |_| { + if full_nodes.iter().all(|&(ref id, ref service, _)| predicate(*id, service)) { + Err(()) + } else { + Ok(()) + } + }) + .timeout(MAX_WAIT_TIME); + + match self.runtime.block_on(interval) { + Ok(()) => unreachable!("interval always fails; qed"), + Err(ref err) if err.is_inner() => (), + Err(_) => panic!("Waited for too long"), + } } } @@ -223,11 +234,15 @@ pub fn connectivity(spec: FactoryChainSpec) { } } -pub fn sync(spec: FactoryChainSpec, block_factory: B, extrinsic_factory: E) +pub fn sync( + spec: FactoryChainSpec, + mut block_factory: B, + mut extrinsic_factory: E, +) where F: ServiceFactory, - B: Fn(&F::FullService) -> ImportBlock, - E: Fn(&F::FullService) -> FactoryExtrinsic, + B: FnMut(&F::FullService) -> ImportBlock, + E: FnMut(&F::FullService) -> FactoryExtrinsic, { const NUM_NODES: u32 = 10; const NUM_BLOCKS: u32 = 512; @@ -265,8 +280,8 @@ pub fn consensus(spec: FactoryChainSpec, authorities: Vec) where F: ServiceFactory, { - const NUM_NODES: u32 = 20; - const NUM_BLOCKS: u32 = 200; + const NUM_NODES: u32 = 10; + const NUM_BLOCKS: u32 = 10; // 10 * 2 sec block production time = ~20 seconds let temp = TempDir::new("substrate-conensus-test").expect("Error creating test dir"); let mut network = TestNet::::new(&temp, spec.clone(), NUM_NODES / 2, 0, authorities, 30600); info!("Checking consensus"); diff --git a/substrate/node/cli/Cargo.toml b/substrate/node/cli/Cargo.toml index 3c46f48f3f..24234fd271 100644 --- a/substrate/node/cli/Cargo.toml +++ b/substrate/node/cli/Cargo.toml @@ -39,6 +39,7 @@ rand = "0.6" finality_tracker = { package = "srml-finality-tracker", path = "../../srml/finality-tracker", default-features = false } [dev-dependencies] +consensus-common = { package = "substrate-consensus-common", path = "../../core/consensus/common" } service-test = { package = "substrate-service-test", path = "../../core/service/test" } [build-dependencies] diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs index 18238eaa12..2ce4a3e656 100644 --- a/substrate/node/cli/src/chain_spec.rs +++ b/substrate/node/cli/src/chain_spec.rs @@ -370,7 +370,7 @@ pub fn local_testnet_config() -> ChainSpec { } #[cfg(test)] -mod tests { +pub(crate) mod tests { use super::*; use service_test; use crate::service::Factory; @@ -381,13 +381,41 @@ mod tests { genesis } + fn local_testnet_genesis_instant_single() -> GenesisConfig { + let mut genesis = testnet_genesis( + vec![ + get_authority_keys_from_seed("Alice"), + ], + get_account_id_from_seed("Alice"), + None, + false, + ); + genesis.timestamp = Some(TimestampConfig { minimum_period: 1 }); + genesis + } + + /// Local testnet config (single validator - Alice) + pub fn integration_test_config_with_single_authority() -> ChainSpec { + ChainSpec::from_genesis( + "Integration Test", + "test", + local_testnet_genesis_instant_single, + vec![], + None, + None, + None, + None, + ) + } + /// Local testnet config (multivalidator Alice + Bob) - pub fn integration_test_config() -> ChainSpec { + pub fn integration_test_config_with_two_authorities() -> ChainSpec { ChainSpec::from_genesis("Integration Test", "test", local_testnet_genesis_instant, vec![], None, None, None, None) } #[test] + #[ignore] fn test_connectivity() { - service_test::connectivity::(integration_test_config()); + service_test::connectivity::(integration_test_config_with_two_authorities()); } } diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs index fa7beb6421..d9db310724 100644 --- a/substrate/node/cli/src/service.rs +++ b/substrate/node/cli/src/service.rs @@ -220,6 +220,23 @@ construct_service_factory! { #[cfg(test)] mod tests { + use std::sync::Arc; + use consensus::CompatibleDigestItem; + use consensus_common::{Environment, Proposer, ImportBlock, BlockOrigin, ForkChoiceStrategy}; + use node_primitives::DigestItem; + use node_runtime::{Call, BalancesCall, UncheckedExtrinsic}; + use parity_codec::{Compact, Encode, Decode}; + use primitives::{ + crypto::Pair as CryptoPair, ed25519::Pair, blake2_256, + sr25519::Public as AddressPublic, + }; + use sr_primitives::{generic::{BlockId, Era, Digest}, traits::{Block, Digest as DigestT}, OpaqueExtrinsic}; + use timestamp; + use finality_tracker; + use keyring::{ed25519::Keyring as AuthorityKeyring, sr25519::Keyring as AccountKeyring}; + use substrate_service::ServiceFactory; + use crate::service::Factory; + #[cfg(feature = "rhd")] fn test_sync() { use {service_test, Factory}; @@ -267,4 +284,107 @@ mod tests { service_test::sync::(chain_spec::integration_test_config(), block_factory, extrinsic_factory); } + #[test] + #[ignore] + fn test_sync() { + let chain_spec = crate::chain_spec::tests::integration_test_config_with_single_authority(); + + let alice = Arc::new(AuthorityKeyring::Alice.pair()); + let mut slot_num = 1u64; + let block_factory = |service: &::FullService| { + let mut inherent_data = service.config.custom.inherent_data_providers + .create_inherent_data().unwrap(); + inherent_data.replace_data(finality_tracker::INHERENT_IDENTIFIER, &1u64); + inherent_data.replace_data(timestamp::INHERENT_IDENTIFIER, &(slot_num * 10)); + + let parent_id = BlockId::number(service.client().info().unwrap().chain.best_number); + let parent_header = service.client().header(&parent_id).unwrap().unwrap(); + let proposer_factory = Arc::new(substrate_basic_authorship::ProposerFactory { + client: service.client(), + transaction_pool: service.transaction_pool(), + }); + let mut digest = Digest::::default(); + digest.push(>::aura_pre_digest(slot_num * 10 / 2)); + let proposer = proposer_factory.init(&parent_header, &[]).unwrap(); + let new_block = proposer.propose( + inherent_data, + digest, + ::std::time::Duration::from_secs(1), + ).expect("Error making test block"); + + let (new_header, new_body) = new_block.deconstruct(); + let pre_hash = new_header.hash(); + // sign the pre-sealed hash of the block and then + // add it to a digest item. + let to_sign = pre_hash.encode(); + let signature = alice.sign(&to_sign[..]); + let item = >::aura_seal( + signature, + ); + slot_num += 1; + + ImportBlock { + origin: BlockOrigin::File, + header: new_header, + justification: None, + post_digests: vec![item], + body: Some(new_body), + finalized: true, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + } + }; + + let bob = Arc::new(AccountKeyring::Bob.pair()); + let charlie = Arc::new(AccountKeyring::Charlie.pair()); + + let mut index = 0; + let extrinsic_factory = |service: &::FullService| { + let amount = 1000; + let to = AddressPublic::from_raw(bob.public().0); + let from = AddressPublic::from_raw(charlie.public().0); + let genesis_hash = service.client().block_hash(0).unwrap().unwrap(); + let signer = charlie.clone(); + + let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); + let era = Era::immortal(); + let raw_payload = (Compact(index), function, era, genesis_hash); + let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { + signer.sign(&blake2_256(payload)[..]) + } else { + signer.sign(payload) + }); + let xt = UncheckedExtrinsic::new_signed( + index, + raw_payload.1, + from.into(), + signature.into(), + era, + ).encode(); + let v: Vec = Decode::decode(&mut xt.as_slice()).unwrap(); + + index += 1; + OpaqueExtrinsic(v) + }; + + service_test::sync::( + chain_spec, + block_factory, + extrinsic_factory, + ); + } + + #[test] + #[ignore] + fn test_consensus() { + use super::Factory; + + service_test::consensus::( + crate::chain_spec::tests::integration_test_config_with_two_authorities(), + vec![ + "//Alice".into(), + "//Bob".into(), + ], + ) + } } diff --git a/substrate/node/primitives/src/lib.rs b/substrate/node/primitives/src/lib.rs index 4dde59296f..2135ad672f 100644 --- a/substrate/node/primitives/src/lib.rs +++ b/substrate/node/primitives/src/lib.rs @@ -57,9 +57,10 @@ pub type Hash = primitives::H256; /// A timestamp: seconds since the unix epoch. pub type Timestamp = u64; +/// Digest item type. +pub type DigestItem = generic::DigestItem; /// Header type. -/// -pub type Header = generic::Header>; +pub type Header = generic::Header; /// Block type. pub type Block = generic::Block; /// Block ID.