diff options
author | Antonio Juarez <antonio.maria.juarez@live.com> | 2014-03-03 22:07:58 +0000 |
---|---|---|
committer | Antonio Juarez <antonio.maria.juarez@live.com> | 2014-03-03 22:07:58 +0000 |
commit | 296ae46ed8f8f6e5f986f978febad302e3df231a (patch) | |
tree | 1629164454a239308f33c9e12afb22e7f3cd8eeb /tests/core_tests/block_validation.cpp | |
parent | changed name (diff) | |
download | monero-296ae46ed8f8f6e5f986f978febad302e3df231a.tar.xz |
moved all stuff to github
Diffstat (limited to 'tests/core_tests/block_validation.cpp')
-rw-r--r-- | tests/core_tests/block_validation.cpp | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp new file mode 100644 index 000000000..36e769c65 --- /dev/null +++ b/tests/core_tests/block_validation.cpp @@ -0,0 +1,613 @@ +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chaingen.h" +#include "chaingen_tests_list.h" + +using namespace epee; +using namespace cryptonote; + +namespace +{ + bool lift_up_difficulty(std::vector<test_event_entry>& events, std::vector<uint64_t>& timestamps, + std::vector<difficulty_type>& cummulative_difficulties, test_generator& generator, + size_t new_block_count, const block blk_last, const account_base& miner_account) + { + difficulty_type commulative_diffic = cummulative_difficulties.empty() ? 0 : cummulative_difficulties.back(); + block blk_prev = blk_last; + for (size_t i = 0; i < new_block_count; ++i) + { + block blk_next; + difficulty_type diffic = next_difficulty(timestamps, cummulative_difficulties); + if (!generator.construct_block_manually(blk_next, blk_prev, miner_account, + test_generator::bf_timestamp | test_generator::bf_diffic, 0, 0, blk_prev.timestamp, crypto::hash(), diffic)) + return false; + + commulative_diffic += diffic; + if (timestamps.size() == DIFFICULTY_WINDOW) + { + timestamps.erase(timestamps.begin()); + cummulative_difficulties.erase(cummulative_difficulties.begin()); + } + timestamps.push_back(blk_next.timestamp); + cummulative_difficulties.push_back(commulative_diffic); + + events.push_back(blk_next); + blk_prev = blk_next; + } + + return true; + } +} + +#define BLOCK_VALIDATION_INIT_GENERATE() \ + GENERATE_ACCOUNT(miner_account); \ + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, 1338224400); + +//---------------------------------------------------------------------------------------------------------------------- +// Tests + +bool gen_block_big_major_version::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_major_ver, CURRENT_BLOCK_MAJOR_VERSION + 1); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_big_minor_version::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_minor_ver, 0, CURRENT_BLOCK_MINOR_VERSION + 1); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_accepted"); + + return true; +} + +bool gen_block_ts_not_checked::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_account, BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - 2); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0r, miner_account, test_generator::bf_timestamp, 0, 0, blk_0.timestamp - 60 * 60); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_accepted"); + + return true; +} + +bool gen_block_ts_in_past::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_account, BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - 1); + + uint64_t ts_below_median = boost::get<block>(events[BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW / 2 - 1]).timestamp; + block blk_1; + generator.construct_block_manually(blk_1, blk_0r, miner_account, test_generator::bf_timestamp, 0, 0, ts_below_median); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_ts_in_future::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_timestamp, 0, 0, time(NULL) + 60*60 + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_invalid_prev_id::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + block blk_1; + crypto::hash prev_id = get_block_hash(blk_0); + reinterpret_cast<char &>(prev_id) ^= 1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_prev_id, 0, 0, 0, prev_id); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_invalid_prev_id::check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*blk*/) +{ + if (1 == event_idx) + return bvc.m_marked_as_orphaned && !bvc.m_added_to_main_chain && !bvc.m_verifivation_failed; + else + return !bvc.m_marked_as_orphaned && bvc.m_added_to_main_chain && !bvc.m_verifivation_failed; +} + +bool gen_block_invalid_nonce::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + std::vector<uint64_t> timestamps; + std::vector<difficulty_type> commulative_difficulties; + if (!lift_up_difficulty(events, timestamps, commulative_difficulties, generator, 2, blk_0, miner_account)) + return false; + + // Create invalid nonce + difficulty_type diffic = next_difficulty(timestamps, commulative_difficulties); + assert(1 < diffic); + const block& blk_last = boost::get<block>(events.back()); + uint64_t timestamp = blk_last.timestamp; + block blk_3; + do + { + ++timestamp; + blk_3.miner_tx.set_null(); + if (!generator.construct_block_manually(blk_3, blk_last, miner_account, + test_generator::bf_diffic | test_generator::bf_timestamp, 0, 0, timestamp, crypto::hash(), diffic)) + return false; + } + while (0 == blk_3.nonce); + --blk_3.nonce; + events.push_back(blk_3); + + return true; +} + +bool gen_block_no_miner_tx::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + transaction miner_tx; + miner_tx.set_null(); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_unlock_time_is_low::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + --miner_tx.unlock_time; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_unlock_time_is_high::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + ++miner_tx.unlock_time; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_unlock_time_is_timestamp_in_past::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.unlock_time = blk_0.timestamp - 10 * 60; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_unlock_time_is_timestamp_in_future::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.unlock_time = blk_0.timestamp + 3 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW * DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_height_is_low::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + boost::get<txin_gen>(miner_tx.vin[0]).height--; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_height_is_high::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + boost::get<txin_gen>(miner_tx.vin[0]).height++; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_has_2_tx_gen_in::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + + txin_gen in; + in.height = get_block_height(blk_0) + 1; + miner_tx.vin.push_back(in); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + REWIND_BLOCKS(events, blk_0r, blk_0, miner_account); + + GENERATE_ACCOUNT(alice); + + tx_source_entry se; + se.amount = blk_0.miner_tx.vout[0].amount; + se.outputs.push_back(std::make_pair(0, boost::get<txout_to_key>(blk_0.miner_tx.vout[0].target).key)); + se.real_output = 0; + se.real_out_tx_key = get_tx_pub_key_from_extra(blk_0.miner_tx); + se.real_output_in_tx_index = 0; + std::vector<tx_source_entry> sources; + sources.push_back(se); + + tx_destination_entry de; + de.addr = miner_account.get_keys().m_account_address; + de.amount = se.amount; + std::vector<tx_destination_entry> destinations; + destinations.push_back(de); + + transaction tmp_tx; + if (!construct_tx(miner_account.get_keys(), sources, destinations, tmp_tx, 0)) + return false; + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.vin.push_back(tmp_tx.vin[0]); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0r, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + // This block has only one output + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_none); + events.push_back(blk_1); + + REWIND_BLOCKS(events, blk_1r, blk_1, miner_account); + + tx_source_entry se; + se.amount = blk_1.miner_tx.vout[0].amount; + se.outputs.push_back(std::make_pair(0, boost::get<txout_to_key>(blk_1.miner_tx.vout[0].target).key)); + se.real_output = 0; + se.real_out_tx_key = get_tx_pub_key_from_extra(blk_1.miner_tx); + se.real_output_in_tx_index = 0; + std::vector<tx_source_entry> sources; + sources.push_back(se); + + tx_destination_entry de; + de.addr = miner_account.get_keys().m_account_address; + de.amount = se.amount; + std::vector<tx_destination_entry> destinations; + destinations.push_back(de); + + transaction tmp_tx; + if (!construct_tx(miner_account.get_keys(), sources, destinations, tmp_tx, 0)) + return false; + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); + miner_tx.vin[0] = tmp_tx.vin[0]; + + block blk_2; + generator.construct_block_manually(blk_2, blk_1r, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_2); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_out_is_small::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.vout[0].amount /= 2; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_out_is_big::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.vout[0].amount *= 2; + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_has_no_out::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + miner_tx.vout.clear(); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_miner_tx_has_out_to_alice::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + GENERATE_ACCOUNT(alice); + + keypair txkey; + MAKE_MINER_TX_AND_KEY_MANUALLY(miner_tx, blk_0, &txkey); + + crypto::key_derivation derivation; + crypto::public_key out_eph_public_key; + crypto::generate_key_derivation(alice.get_keys().m_account_address.m_view_public_key, txkey.sec, derivation); + crypto::derive_public_key(derivation, 1, alice.get_keys().m_account_address.m_spend_public_key, out_eph_public_key); + + tx_out out_to_alice; + out_to_alice.amount = miner_tx.vout[0].amount / 2; + miner_tx.vout[0].amount -= out_to_alice.amount; + out_to_alice.target = txout_to_key(out_eph_public_key); + miner_tx.vout.push_back(out_to_alice); + + block blk_1; + generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_accepted"); + + return true; +} + +bool gen_block_has_invalid_tx::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + std::vector<crypto::hash> tx_hashes; + tx_hashes.push_back(crypto::hash()); + + block blk_1; + generator.construct_block_manually_tx(blk_1, blk_0, miner_account, tx_hashes, 0); + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +bool gen_block_is_too_big::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + // Creating a huge miner_tx, it will have a lot of outs + MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); + static const size_t tx_out_count = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE / 2; + uint64_t amount = get_outs_money_amount(miner_tx); + uint64_t portion = amount / tx_out_count; + uint64_t remainder = amount % tx_out_count; + txout_target_v target = miner_tx.vout[0].target; + miner_tx.vout.clear(); + for (size_t i = 0; i < tx_out_count; ++i) + { + tx_out o; + o.amount = portion; + o.target = target; + miner_tx.vout.push_back(o); + } + if (0 < remainder) + { + tx_out o; + o.amount = remainder; + o.target = target; + miner_tx.vout.push_back(o); + } + + // Block reward will be incorrect, as it must be reduced if cumulative block size is very big, + // but in this test it doesn't matter + block blk_1; + if (!generator.construct_block_manually(blk_1, blk_0, miner_account, test_generator::bf_miner_tx, 0, 0, 0, crypto::hash(), 0, miner_tx)) + return false; + + events.push_back(blk_1); + + DO_CALLBACK(events, "check_block_purged"); + + return true; +} + +gen_block_invalid_binary_format::gen_block_invalid_binary_format() + : m_corrupt_blocks_begin_idx(0) +{ + REGISTER_CALLBACK("check_all_blocks_purged", gen_block_invalid_binary_format::check_all_blocks_purged); + REGISTER_CALLBACK("corrupt_blocks_boundary", gen_block_invalid_binary_format::corrupt_blocks_boundary); +} + +bool gen_block_invalid_binary_format::generate(std::vector<test_event_entry>& events) const +{ + BLOCK_VALIDATION_INIT_GENERATE(); + + std::vector<uint64_t> timestamps; + std::vector<difficulty_type> cummulative_difficulties; + difficulty_type cummulative_diff = 1; + + // Unlock blk_0 outputs + block blk_last = blk_0; + assert(CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW < DIFFICULTY_WINDOW); + for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) + { + MAKE_NEXT_BLOCK(events, blk_curr, blk_last, miner_account); + timestamps.push_back(blk_curr.timestamp); + cummulative_difficulties.push_back(++cummulative_diff); + blk_last = blk_curr; + } + + // Lifting up takes a while + difficulty_type diffic; + do + { + blk_last = boost::get<block>(events.back()); + diffic = next_difficulty(timestamps, cummulative_difficulties); + if (!lift_up_difficulty(events, timestamps, cummulative_difficulties, generator, 1, blk_last, miner_account)) + return false; + std::cout << "Block #" << events.size() << ", difficulty: " << diffic << std::endl; + } + while (diffic < 1500); + + blk_last = boost::get<block>(events.back()); + MAKE_TX(events, tx_0, miner_account, miner_account, MK_COINS(120), boost::get<block>(events[1])); + DO_CALLBACK(events, "corrupt_blocks_boundary"); + + block blk_test; + std::vector<crypto::hash> tx_hashes; + tx_hashes.push_back(get_transaction_hash(tx_0)); + size_t txs_size = get_object_blobsize(tx_0); + diffic = next_difficulty(timestamps, cummulative_difficulties); + if (!generator.construct_block_manually(blk_test, blk_last, miner_account, + test_generator::bf_diffic | test_generator::bf_timestamp | test_generator::bf_tx_hashes, 0, 0, blk_last.timestamp, + crypto::hash(), diffic, transaction(), tx_hashes, txs_size)) + return false; + + blobdata blob = t_serializable_object_to_blob(blk_test); + for (size_t i = 0; i < blob.size(); ++i) + { + for (size_t bit_idx = 0; bit_idx < sizeof(blobdata::value_type) * 8; ++bit_idx) + { + serialized_block sr_block(blob); + blobdata::value_type& ch = sr_block.data[i]; + ch ^= 1 << bit_idx; + + events.push_back(sr_block); + } + } + + DO_CALLBACK(events, "check_all_blocks_purged"); + + return true; +} + +bool gen_block_invalid_binary_format::check_block_verification_context(const cryptonote::block_verification_context& bvc, + size_t event_idx, const cryptonote::block& blk) +{ + if (0 == m_corrupt_blocks_begin_idx || event_idx < m_corrupt_blocks_begin_idx) + { + return bvc.m_added_to_main_chain; + } + else + { + return !bvc.m_added_to_main_chain && (bvc.m_already_exists || bvc.m_marked_as_orphaned || bvc.m_verifivation_failed); + } +} + +bool gen_block_invalid_binary_format::corrupt_blocks_boundary(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events) +{ + m_corrupt_blocks_begin_idx = ev_index + 1; + return true; +} + +bool gen_block_invalid_binary_format::check_all_blocks_purged(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_block_invalid_binary_format::check_all_blocks_purged"); + + CHECK_EQ(1, c.get_pool_transactions_count()); + CHECK_EQ(m_corrupt_blocks_begin_idx - 2, c.get_current_blockchain_height()); + + return true; +} |