diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 43e3720d2..0fc22ddfc 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -23,8 +23,6 @@ use spec::*; use engine::*; use evm::Schedule; use evm::Factory; -#[cfg(test)] -use tests::helpers::*; /// Engine using Ethash proof-of-work consensus algorithm, suitable for Ethereum /// mainnet chains in the Olympic, Frontier and Homestead eras. @@ -49,6 +47,17 @@ impl Ethash { }) } + #[cfg(test)] + fn new_test(spec: Spec) -> Ethash { + Ethash { + spec: spec, + pow: EthashManager::new(), + factory: Factory::default(), + u64_params: RwLock::new(HashMap::new()), + u256_params: RwLock::new(HashMap::new()) + } + } + fn u64_param(&self, name: &str) -> u64 { *self.u64_params.write().unwrap().entry(name.to_owned()).or_insert_with(|| self.spec().engine_params.get(name).map_or(0u64, |a| decode(&a))) @@ -123,6 +132,11 @@ impl Engine for Ethash { fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { // check the seal fields. + if header.seal.len() != self.seal_fields() { + return Err(From::from(BlockError::InvalidSealArity( + Mismatch { expected: self.seal_fields(), found: header.seal.len() } + ))); + } try!(UntrustedRlp::new(&header.seal[0]).as_val::()); try!(UntrustedRlp::new(&header.seal[1]).as_val::()); @@ -143,6 +157,11 @@ impl Engine for Ethash { } fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { + if header.seal.len() != self.seal_fields() { + return Err(From::from(BlockError::InvalidSealArity( + Mismatch { expected: self.seal_fields(), found: header.seal.len() } + ))); + } let result = self.pow.compute_light(header.number as u64, &Ethash::to_ethash(header.bare_hash()), header.nonce().low_u64()); let mix = Ethash::from_ethash(result.mix_hash); let difficulty = Ethash::boundary_to_difficulty(&Ethash::from_ethash(result.value)); @@ -242,38 +261,187 @@ impl Header { } } -#[test] -fn on_close_block() { +#[cfg(test)] +mod tests { + extern crate ethash; + + use common::*; + use block::*; + use engine::*; + use tests::helpers::*; use super::*; - let engine = new_morden().to_engine().unwrap(); - let genesis_header = engine.spec().genesis_header(); - let mut db_result = get_temp_journal_db(); - let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let last_hashes = vec![genesis_header.hash()]; - let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); - let b = b.close(); - assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); + use super::super::new_morden; + + #[test] + fn on_close_block() { + let engine = new_morden().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(&mut db); + let last_hashes = vec![genesis_header.hash()]; + let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let b = b.close(); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); + } + + #[test] + fn on_close_block_with_uncle() { + let engine = new_morden().to_engine().unwrap(); + let genesis_header = engine.spec().genesis_header(); + let mut db_result = get_temp_journal_db(); + let mut db = db_result.take(); + engine.spec().ensure_db_good(&mut db); + let last_hashes = vec![genesis_header.hash()]; + let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); + let mut uncle = Header::new(); + let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); + uncle.author = uncle_author.clone(); + b.push_uncle(uncle).unwrap(); + + let b = b.close(); + assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap()); + assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap()); + } + + #[test] + fn has_valid_metadata() { + let engine = Ethash::new_boxed(new_morden()); + assert!(!engine.name().is_empty()); + assert!(engine.version().major >= 1); + } + + #[test] + fn can_return_params() { + let engine = Ethash::new_test(new_morden()); + assert!(engine.u64_param("durationLimit") > 0); + assert!(engine.u256_param("minimumDifficulty") > U256::zero()); + } + + #[test] + fn can_return_factory() { + let engine = Ethash::new_test(new_morden()); + engine.vm_factory(); + } + + #[test] + fn can_return_schedule() { + let engine = Ethash::new_test(new_morden()); + let schedule = engine.schedule(&EnvInfo { + number: 10000000, + author: x!(0), + timestamp: 0, + difficulty: x!(0), + last_hashes: vec![], + gas_used: x!(0), + gas_limit: x!(0) + }); + + assert!(schedule.stack_limit > 0); + + let schedule = engine.schedule(&EnvInfo { + number: 100, + author: x!(0), + timestamp: 0, + difficulty: x!(0), + last_hashes: vec![], + gas_used: x!(0), + gas_limit: x!(0) + }); + + assert!(!schedule.have_delegate_call); + } + + #[test] + fn can_do_seal_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let header: Header = Header::default(); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_difficulty_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::DifficultyOutOfBounds(_))) => {}, + Err(_) => { panic!("should be block difficulty error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_proof_of_work_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); + + let verify_result = engine.verify_block_basic(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(_) => { panic!("should be invalid proof of work error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_seal_unordered_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let header: Header = Header::default(); + + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidSealArity(_))) => {}, + Err(_) => { panic!("should be block seal-arity mismatch error (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_seal256_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::zero()).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::MismatchedH256SealElement(_))) => {}, + Err(_) => { panic!("should be invalid 256-bit seal fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + } + + #[test] + fn can_do_proof_of_work_unordered_verification_fail() { + let engine = Ethash::new_test(new_morden()); + let mut header: Header = Header::default(); + header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).to_vec(), rlp::encode(&H64::zero()).to_vec()]); + header.set_difficulty(U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffaaaaaaaaaaaaaaaaaaaa").unwrap()); + + let verify_result = engine.verify_block_unordered(&header, None); + + match verify_result { + Err(Error::Block(BlockError::InvalidProofOfWork(_))) => {}, + Err(_) => { panic!("should be invalid proof-of-work fail (got {:?})", verify_result); }, + _ => { panic!("Should be error, got Ok"); }, + } + + } + + // TODO: difficulty test } -#[test] -fn on_close_block_with_uncle() { - use super::*; - let engine = new_morden().to_engine().unwrap(); - let genesis_header = engine.spec().genesis_header(); - let mut db_result = get_temp_journal_db(); - let mut db = db_result.take(); - engine.spec().ensure_db_good(&mut db); - let last_hashes = vec![genesis_header.hash()]; - let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]); - let mut uncle = Header::new(); - let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); - uncle.author = uncle_author.clone(); - b.push_uncle(uncle).unwrap(); - - let b = b.close(); - assert_eq!(b.state().balance(&Address::zero()), U256::from_str("478eae0e571ba000").unwrap()); - assert_eq!(b.state().balance(&uncle_author), U256::from_str("3cb71f51fc558000").unwrap()); -} - -// TODO: difficulty test diff --git a/ethcore/src/evm/factory.rs b/ethcore/src/evm/factory.rs index f1be0e427..4a9bd38ba 100644 --- a/ethcore/src/evm/factory.rs +++ b/ethcore/src/evm/factory.rs @@ -159,11 +159,13 @@ macro_rules! evm_test_ignore( #[test] #[ignore] #[cfg(feature = "jit")] + #[cfg(feature = "ignored-tests")] fn $name_jit() { $name_test(Factory::new(VMType::Jit)); } #[test] #[ignore] + #[cfg(feature = "ignored-tests")] fn $name_int() { $name_test(Factory::new(VMType::Interpreter)); } diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index 2d6039953..812dc3acd 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -360,6 +360,7 @@ impl<'a> Executive<'a> { } #[cfg(test)] +#[allow(dead_code)] mod tests { use super::*; use common::*; @@ -599,6 +600,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_aba_calls: test_aba_calls_jit, test_aba_calls_int} fn test_aba_calls(factory: Factory) { // 60 00 - push 0 @@ -659,6 +661,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_recursive_bomb1: test_recursive_bomb1_jit, test_recursive_bomb1_int} fn test_recursive_bomb1(factory: Factory) { // 60 01 - push 1 @@ -704,6 +707,7 @@ mod tests { } // test is incorrect, mk + // TODO: fix (preferred) or remove evm_test_ignore!{test_transact_simple: test_transact_simple_jit, test_transact_simple_int} fn test_transact_simple(factory: Factory) { let keypair = KeyPair::create().unwrap(); @@ -902,5 +906,4 @@ mod tests { } } } - } diff --git a/ethcore/src/json_tests/mod.rs b/ethcore/src/json_tests/mod.rs index 1cae0fa1d..df67de76d 100644 --- a/ethcore/src/json_tests/mod.rs +++ b/ethcore/src/json_tests/mod.rs @@ -20,7 +20,6 @@ mod test_common; mod transaction; mod executive; mod state; -mod client; mod chain; mod homestead_state; mod homestead_chain; diff --git a/ethcore/src/json_tests/client.rs b/ethcore/src/tests/client.rs similarity index 99% rename from ethcore/src/json_tests/client.rs rename to ethcore/src/tests/client.rs index 2d3166c74..697647187 100644 --- a/ethcore/src/json_tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . use client::{BlockChainClient,Client}; -use super::test_common::*; use tests::helpers::*; +use common::*; #[test] fn created() { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 9ec36fa93..f5815b718 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -#[cfg(feature = "json-tests")] use client::{BlockChainClient, Client}; use std::env; use common::*; @@ -134,7 +133,6 @@ pub fn create_test_block_with_data(header: &Header, transactions: &[&SignedTrans rlp.out() } -#[cfg(feature = "json-tests")] pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult> { let dir = RandomTempPath::new(); @@ -174,7 +172,6 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult } } -#[cfg(feature = "json-tests")] pub fn get_test_client_with_blocks(blocks: Vec) -> GuardedTempResult> { let dir = RandomTempPath::new(); let client = Client::new(get_test_spec(), dir.as_path(), IoChannel::disconnected()).unwrap(); @@ -271,7 +268,6 @@ pub fn get_good_dummy_block() -> Bytes { create_test_block(&block_header) } -#[cfg(feature = "json-tests")] pub fn get_bad_state_dummy_block() -> Bytes { let mut block_header = Header::new(); let test_spec = get_test_spec(); diff --git a/ethcore/src/tests/mod.rs b/ethcore/src/tests/mod.rs index a4e13730a..28c1b3b5b 100644 --- a/ethcore/src/tests/mod.rs +++ b/ethcore/src/tests/mod.rs @@ -15,3 +15,4 @@ // along with Parity. If not, see . pub mod helpers; +mod client; \ No newline at end of file