From 66fd58b8ee64a2d0fb56a39c070134c745a73dd5 Mon Sep 17 00:00:00 2001 From: sowle Date: Sat, 1 Jun 2024 21:20:58 +0200 Subject: [PATCH] coretests: many altchain tests adapted for post-HF4: pos_altblocks_validation chain_switching_when_gindex_spent_in_both_chains alt_blocks_validation_and_same_new_amount_in_two_txs alt_blocks_with_the_same_txs chain_switching_when_out_spent_in_alt_chain_mixin chain_switching_when_out_spent_in_alt_chain_ref_id --- tests/core_tests/chain_switch_1.cpp | 109 +++++++++++++++++------ tests/core_tests/chaingen_main.cpp | 12 +-- tests/core_tests/pos_validation.cpp | 130 ++++++++++++++++++---------- 3 files changed, 169 insertions(+), 82 deletions(-) diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp index a579515f..2c830dd6 100644 --- a/tests/core_tests/chain_switch_1.cpp +++ b/tests/core_tests/chain_switch_1.cpp @@ -422,6 +422,15 @@ bool chain_switching_when_gindex_spent_in_both_chains::generate(std::vector sources; - r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + TESTS_DEFAULT_FEE, 0); + r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + 2*TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); std::vector destinations; - destinations.push_back(tx_destination_entry(new_amount, miner_acc.get_public_address())); // no cashback, just payment + destinations.push_back(tx_destination_entry(new_amount, miner_acc.get_public_address())); + destinations.push_back(tx_destination_entry(TESTS_DEFAULT_FEE, miner_acc.get_public_address())); //just to make two outputs (to please HF4 rules) transaction tx_1 = AUTO_VAL_INIT(tx_1); uint64_t tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); - events.push_back(tx_1); + ADD_CUSTOM_EVENT(events, tx_1); // second tx sources.clear(); - r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + TESTS_DEFAULT_FEE, 0, sources); + r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), new_amount + 2*TESTS_DEFAULT_FEE, 0, sources); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); transaction tx_2 = AUTO_VAL_INIT(tx_2); // use the same destinations tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); - events.push_back(tx_2); + ADD_CUSTOM_EVENT(events, tx_2); // make an alt block with these txs MAKE_NEXT_BLOCK_TX_LIST(events, blk_3a, blk_2a, miner_acc, std::list({ tx_1, tx_2 })); @@ -565,10 +577,19 @@ alt_blocks_with_the_same_txs::alt_blocks_with_the_same_txs() bool alt_blocks_with_the_same_txs::generate(std::vector& events) const { - // Test idea: check that many two alt blocks having the same tx are correctly handled with respect to is_tx_related_to_altblock() + // Test idea: check that two alt blocks having the same tx are correctly handled with respect to is_tx_related_to_altblock() GENERATE_ACCOUNT(miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks + if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 2)) + { + // HF4 requires tests_random_split_strategy (for 2 outputs minimum) + test_gentime_settings tgts = generator.get_test_gentime_settings(); + tgts.split_strategy = tests_random_split_strategy; + generator.set_test_gentime_settings(tgts); + } + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner_acc); REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); @@ -634,15 +655,24 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector& events) const { - random_state_test_restorer::reset_random(0); // to make the test deterministic + //random_state_test_restorer::reset_random(0); // to make the test deterministic uint64_t ts = 1450000000; test_core_time::adjust(ts); @@ -701,15 +735,24 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector destinations; - destinations.push_back(tx_destination_entry(MK_TEST_COINS(4), bob_acc.get_public_address())); + destinations.push_back(tx_destination_entry(MK_TEST_COINS(3), bob_acc.get_public_address())); + destinations.push_back(tx_destination_entry(MK_TEST_COINS(1), bob_acc.get_public_address())); size_t nmix = 3; - r = construct_tx_to_key(m_hardforks, events, tx_1, blk_2a, alice_acc, destinations, TESTS_DEFAULT_FEE, nmix, 0, empty_extra, empty_attachment, true, true, true); + r = construct_tx_to_key(m_hardforks, events, tx_1, blk_2ar, alice_acc, destinations, TESTS_DEFAULT_FEE, nmix, 0, empty_extra, empty_attachment, true, true, true /* use_ref_by_id */); CHECK_AND_ASSERT_MES(r, false, "construct_tx_to_key failed"); // make sure tx_1 really use ref_by_id @@ -748,17 +796,22 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector& events) @@ -871,23 +871,26 @@ bool pos_altblocks_validation::generate(std::vector& events) c std::list miner_acc_lst(1, miner_acc); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); - MAKE_NEXT_BLOCK(events, blk_1, blk_0, alice_acc); + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_NEXT_BLOCK(events, blk_1, blk_0r, alice_acc); REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + bool HF4_active = m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, get_block_height(blk_1r) + 1); + MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc); const transaction& stake_tx = blk_1.miner_tx; - uint64_t alice_money = get_outs_money_amount(stake_tx); uint64_t stake_tx_out_id = 0; - // select stake_tx_out_id as an output with the biggest amount - for (size_t i = 1; i < stake_tx.vout.size(); ++i) - { - if (boost::get(stake_tx.vout[i]).amount >boost::get( stake_tx.vout[stake_tx_out_id]).amount) - stake_tx_out_id = i; - } + uint64_t alice_money = decode_native_output_amount_or_throw(alice_acc, blk_1.miner_tx, stake_tx_out_id); + //// select stake_tx_out_id as an output with the biggest amount + //for (size_t i = 1; i < stake_tx.vout.size(); ++i) + //{ + // if (boost::get(stake_tx.vout[i]).amount > boost::get( stake_tx.vout[stake_tx_out_id]).amount) + // stake_tx_out_id = i; + //} MAKE_TX_FEE(events, tx_0, alice_acc, alice_acc, alice_money - TESTS_DEFAULT_FEE * 17, TESTS_DEFAULT_FEE * 17, blk_2); // tx_0 transfers all Alice's money, so it effectevily spends all outputs in stake_ts, make sure it does - CHECK_AND_ASSERT_MES(tx_0.vin.size() == stake_tx.vout.size(), false, "probably, tx_0 doesn't spend all Alice's money as expected, tx_0.vin.size()=" << tx_0.vin.size() << ", stake_tx.vout.size()=" << stake_tx.vout.size()); + //CHECK_AND_ASSERT_MES(tx_0.vin.size() == stake_tx.vout.size(), false, "probably, tx_0 doesn't spend all Alice's money as expected, tx_0.vin.size()=" << tx_0.vin.size() << ", stake_tx.vout.size()=" << stake_tx.vout.size()); MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_0); @@ -900,12 +903,13 @@ bool pos_altblocks_validation::generate(std::vector& events) c REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); MAKE_NEXT_POS_BLOCK(events, blk_4, blk_3r, miner_acc, miner_acc_lst); MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc); + MAKE_NEXT_POS_BLOCK(events, blk_6, blk_5, miner_acc, miner_acc_lst); - // 0 1 11 12 13 23 24 25 <- height + // 0 11 21 22 23 33 34 35 36 <- height // // +------- blk_1 mined by Alice // | - // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain + // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain // | tx_0 // +---<<---uses-blk_1-out--+ @@ -915,38 +919,60 @@ bool pos_altblocks_validation::generate(std::vector& events) c block blk_2a = AUTO_VAL_INIT(blk_2a); r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_1r, stake_tx, stake_tx_out_id, blk_2a); CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); - events.push_back(blk_2a); + ADD_CUSTOM_EVENT(events, blk_2a); CHECK_AND_ASSERT_MES(generator.add_block_info(blk_2a, std::list()), false, "add_block_info failed"); - // 0 1 11 12 13 23 24 25 <- height + // 0 11 21 22 23 33 34 35 36 <- height // // +-----------------------+ - // | tx_0 tx_0 spends all outputs in blk_1 (main chain) - // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain + // | tx_0 tx_0 spends all outputs in blk_1 (main chain) + // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain // | \ - // | \- (2a)- <- alt chain - // +--------------+ PoS block 2a uses stake already spent in main chain + // | \- (2a)- <- alt chain + // +--------------+ PoS block 2a uses stake already spent in main chain - // Case 2 (should fail) + // Case 2a (should fail) // alt PoS block (blk_3a) refers in its coinstake to an output (stake_tx_out_id) already spent in this alt chain (in blk_2a) block blk_3a = AUTO_VAL_INIT(blk_3a); r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_2a, stake_tx, stake_tx_out_id, blk_3a); CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); DO_CALLBACK(events, "mark_invalid_block"); - events.push_back(blk_3a); + ADD_CUSTOM_EVENT(events, blk_3a); - // 0 1 11 12 13 23 24 25 <- height + // 0 11 21 22 23 33 34 35 36 <- height // // +-----------------------+ - // | tx_0 tx_0 spends all outputs in blk_1 (main chain) - // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- <- main chain + // | tx_0 tx_0 spends all outputs in blk_1 (main chain) + // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain // || \ - // || \- (2a)- #3a#- <- alt chain - // |+--------------+ | PoS block 2a uses stake already spent in main chain (okay) - // +-----------------------+ PoS block 3a uses stake already spent in current alt chain (fail) + // || \- (2a)- #3a#- <- alt chain + // |+--------------+ | PoS block 2a uses stake already spent in main chain (okay) + // +-----------------------+ PoS block 3a uses stake already spent in current alt chain (fail) + // Case 2b (should fail) + // alt PoS block (blk_3aa) has invalid signature + block blk_3aa{}; + r = generate_pos_block_with_given_coinstake(generator, events, miner_acc, blk_2a, blk_0r.miner_tx, 0, blk_3aa); + CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); + if (HF4_active) + boost::get(blk_3aa.miner_tx.signatures[0]).y0.m_u64[1] = 5; // invalidate signature + else + boost::get(blk_3aa.miner_tx.signatures[0]).s[0].c.data[5] = 7; // invalidate signature + DO_CALLBACK(events, "mark_invalid_block"); + ADD_CUSTOM_EVENT(events, blk_3aa); + + // 0 11 21 22 23 33 34 35 36 <- height + // + // +-----------------------+ + // | tx_0 tx_0 spends all outputs in blk_1 (main chain) + // (0 )- (1 )-...(1r)- (2 )- (3 )-...(3r)- (4 )- (5 )- (6 )- <- main chain + // || \ + // || \- (2a)- #3aa#- <- alt chain + // |+--------------+ | PoS block 2a uses stake already spent in main chain (okay) + // +-----------------------+ PoS block 3aa has incorrect signature (fail) + REWIND_BLOCKS_N_WITH_TIME(events, blk_2br, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // Case 3 (should pass) @@ -954,55 +980,63 @@ bool pos_altblocks_validation::generate(std::vector& events) c block blk_3b = AUTO_VAL_INIT(blk_3b); r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_2br, blk_2a.miner_tx, 0, blk_3b); CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); - events.push_back(blk_3b); + ADD_CUSTOM_EVENT(events, blk_3b); CHECK_AND_ASSERT_MES(generator.add_block_info(blk_3b, std::list()), false, "add_block_info failed"); - // 0 1 11 12 13 22 23 24 25 <- height + // 0 11 21 22 23 33 34 35 36 <- height // // +-----------------------+ - // | tx_0 tx_0 spends all outputs in blk_1 (main chain) - // (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- <- main chain + // | tx_0 tx_0 spends all outputs in blk_1 (main chain) + // (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- (6 )- <- main chain // || \ - // || \- (2a)- #3a#- <- alt chain - // |+--------------+ \ | PoS block 2a uses stake already spent in main chain (okay) - // +---------------|-------+ PoS block 3a uses stake already spent in current alt chain (fail) + // || \- (2a)- #3a#- <- alt chain + // |+--------------+ \ | PoS block 2a uses stake already spent in main chain (okay) + // +---------------|-------+ PoS block 3a uses stake already spent in current alt chain (fail) // | \ - // | \ ...... (2br)- (3b)- <- alt chain + // | \ ...... (2br)- (3b)- <- alt chain // | | - // +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a) + // +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a) // Case 4 (should fail) // alt PoS block (blk_4b) in its coinstake refers to an output (tx_0) that appeared in the main chain (blk_3) above split height block blk_4b = AUTO_VAL_INIT(blk_4b); r = generate_pos_block_with_given_coinstake(generator, events, alice_acc, blk_3b, tx_0, tx_0_some_output_idx, blk_4b, tx_0_some_output_gindex); - CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); - DO_CALLBACK(events, "mark_invalid_block"); - events.push_back(blk_4b); + if (HF4_active) + { + CHECK_AND_ASSERT_MES(!r, false, "generate_pos_block_with_given_coinstake not failed as expected"); + } + else + { + CHECK_AND_ASSERT_MES(r, false, "generate_pos_block_with_given_coinstake failed"); + DO_CALLBACK(events, "mark_invalid_block"); + ADD_CUSTOM_EVENT(events, blk_4b); + } - // 0 1 11 12 13 22 23 24 25 <- height + // 0 11 21 22 23 33 34 35 36 <- height // +------------------+ // +-----------------------+ | | - // | tx_0 | tx_0 spends all outputs in blk_1 (main chain) - // (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- <- main chain + // | tx_0 | tx_0 spends all outputs in blk_1 (main chain) + // (0 )- (1 )-...(1r)- (2 )- (3 )- ........ (3r)- (4 )- (5 )- (6 )- <- main chain // || \ | - // || \- (2a)- #3a#- | <- alt chain - // |+--------------+ \ | \ PoS block 2a uses stake already spent in main chain (okay) - // +---------------|-------+ \ PoS block 3a uses stake already spent in current alt chain (fail) + // || \- (2a)- #3a#- | <- alt chain + // |+--------------+ \ | \ PoS block 2a uses stake already spent in main chain (okay) + // +---------------|-------+ \ PoS block 3a uses stake already spent in current alt chain (fail) // | \ \ - // | \ ...... (2br)- (3b)- #4b# <- alt chain + // | \ ...... (2br)- (3b)- #4b# <- alt chain // | | - // +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a) + // +-----------------------+ PoS block 3b uses as stake an output, created in current alt chain (2a) - DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_5), get_block_hash(blk_5))); + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6), get_block_hash(blk_6))); // Final check: switch the chains MAKE_NEXT_BLOCK(events, blk_4c, blk_3b, miner_acc); MAKE_NEXT_BLOCK(events, blk_5c, blk_4c, miner_acc); MAKE_NEXT_BLOCK(events, blk_6c, blk_5c, miner_acc); + MAKE_NEXT_BLOCK(events, blk_7c, blk_6c, miner_acc); - DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_6c), get_block_hash(blk_6c))); + DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_7c), get_block_hash(blk_7c))); size_t txs_count = 1; DO_CALLBACK_PARAMS(events, "check_tx_pool_count", txs_count); // tx_0 should left in the pool