1
0
Fork 0
forked from lthn/blockchain

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
This commit is contained in:
sowle 2024-06-01 21:20:58 +02:00
parent 7da72fcc89
commit 66fd58b8ee
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
3 changed files with 169 additions and 82 deletions

View file

@ -422,6 +422,15 @@ bool chain_switching_when_gindex_spent_in_both_chains::generate(std::vector<test
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_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, alice_acc);
REWIND_BLOCKS_N(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
@ -499,6 +508,8 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector<
GENERATE_ACCOUNT(miner_acc);
GENERATE_ACCOUNT(alice_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
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);
@ -516,26 +527,27 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector<
// make two txs with one output (huge fee, probably - doesn't matter) with amount that is never seen before
std::vector<tx_source_entry> 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<tx_destination_entry> 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<transaction>({ 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<test_event_entry>& 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<tes
GENERATE_ACCOUNT(alice_acc);
GENERATE_ACCOUNT(bob_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);
// 0 1 11 12 13 14
// (0 )- (1 )-...(1r)- (2 )- (3 )- <-- main chain
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
// \
// \
// \- (2a)- (3a)- (4a)-
// tx_0 <- tx_1 // tx_1 spends output from tx_0
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends output from tx_0
// send batch of 10 x 5 test coins to Alice for easier tx_1 construction (and to generate free decoys)
transaction tx_0;
@ -652,17 +682,21 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
events.push_back(tx_0);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc);
// altchain
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_0);
REWIND_BLOCKS_N(events, blk_2ar, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2a, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2ar, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(50));
// Alice spends her 5 test coins received by tx_0
MAKE_TX_FEE_MIX(events, tx_1, alice_acc, bob_acc, MK_TEST_COINS(4), TESTS_DEFAULT_FEE, 3 /* nmix */, blk_2a);
MAKE_TX_FEE_MIX(events, tx_1, alice_acc, bob_acc, MK_TEST_COINS(4), TESTS_DEFAULT_FEE, 3 /* nmix */, blk_2ar);
events.pop_back(); // pop back tx_1 as it won't go into the tx pool normally because of alt chain
// simulate handling a block with that tx: handle tx like going with the block...
@ -670,7 +704,7 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
events.push_back(tx_1);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2a, miner_acc, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2ar, miner_acc, tx_1);
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
// make sure Alice has correct balance
@ -687,7 +721,7 @@ bool chain_switching_when_out_spent_in_alt_chain_mixin::generate(std::vector<tes
bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<test_event_entry>& 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<te
bob_acc.set_createtime(ts);
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);
// 0 1 11 12 13 14
// (0 )- (1 )-...(1r)- (2 )- (3 )- <- main chain
// 0 1 11 12 22 23 24
// (0 )- (1 )-...(1r)- (2 )-...(2r)- (3 )- <-- main chain
// \
// \
// \- (2a)- (3a)- (4a)-
// tx_0 <- tx_1 // tx_1 spends an output from tx_0 using ref_by_id and mixins
// \- (2a)-...(2ar)- (3a)- (4a)-
// tx_0 <-------- tx_1 // tx_1 spends an output from tx_0 using ref_by_id and mixins
// send batch of 10 x 5 test coins to Alice for easier tx_0 construction
transaction tx_0;
@ -722,24 +765,29 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector<te
count_ref_by_id_and_gindex_refs_for_tx_inputs(tx_0, refs_count, gindex_count);
CHECK_AND_ASSERT_MES(refs_count == 1 && gindex_count == 0, false, "incorrect input references: " << refs_count << ", " << gindex_count);
events.push_back(tx_0);
ADD_CUSTOM_EVENT(events, tx_0);
MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
REWIND_BLOCKS_N(events, blk_2r, blk_2, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
MAKE_NEXT_BLOCK(events, blk_3, blk_2r, miner_acc);
// altchain
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_0);
REWIND_BLOCKS_N(events, blk_2ar, blk_2a, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // this was added to adapt test to HF4 rule of min 10 blocks age to be spent, condiser rewriting the test in future to simplify this -- sowle
// make sure Alice received exactly 50 test coins
CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2a, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_2ar, 2*CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(50));
// Alice spends her 5 test coins received by tx_0
transaction tx_1;
std::vector<tx_destination_entry> 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<te
CHECK_AND_ASSERT_MES(refs_count == nmix + 1 && gindex_count == 0, false, "incorrect input references: " << refs_count << ", " << gindex_count);
// simulate handling a block with that tx: handle tx like going with the block...
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
events.push_back(tx_1);
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true));
ADD_CUSTOM_EVENT(events, tx_1);
ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2a, miner_acc, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_3a, blk_2ar, miner_acc, tx_1);
MAKE_NEXT_BLOCK(events, blk_4a, blk_3a, miner_acc);
// make sure Alice has correct balance
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_4a, 2);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, MK_TEST_COINS(45));
// make sure Bob has correct balance
CREATE_TEST_WALLET(bob_wlt, bob_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_4a, 2*CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 4);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, MK_TEST_COINS(4));
// make sure chain successfully switched
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_4a), get_block_hash(blk_4a)));

View file

@ -1122,7 +1122,7 @@ int main(int argc, char* argv[])
//GENERATE_AND_PLAY(pos_emission_test); // Long test! by demand only
GENERATE_AND_PLAY(pos_wallet_big_block_test);
//GENERATE_AND_PLAY(block_template_against_txs_size); // Long test! by demand only
GENERATE_AND_PLAY(pos_altblocks_validation);
GENERATE_AND_PLAY_HF(pos_altblocks_validation, "3-*");
GENERATE_AND_PLAY_HF(pos_mining_with_decoys, "3");
// alternative blocks and generic chain-switching tests
@ -1131,13 +1131,13 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_chain_switch_1);
GENERATE_AND_PLAY(bad_chain_switching_with_rollback);
GENERATE_AND_PLAY(chain_switching_and_tx_with_attachment_blobsize);
GENERATE_AND_PLAY(chain_switching_when_gindex_spent_in_both_chains);
GENERATE_AND_PLAY_HF(chain_switching_when_gindex_spent_in_both_chains, "3-*");
GENERATE_AND_PLAY(alt_chain_coins_pow_mined_then_spent);
GENERATE_AND_PLAY(gen_simple_chain_split_1);
GENERATE_AND_PLAY(alt_blocks_validation_and_same_new_amount_in_two_txs);
GENERATE_AND_PLAY(alt_blocks_with_the_same_txs);
GENERATE_AND_PLAY(chain_switching_when_out_spent_in_alt_chain_mixin);
GENERATE_AND_PLAY(chain_switching_when_out_spent_in_alt_chain_ref_id);
GENERATE_AND_PLAY_HF(alt_blocks_validation_and_same_new_amount_in_two_txs, "3-*");
GENERATE_AND_PLAY_HF(alt_blocks_with_the_same_txs, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_mixin, "3-*");
GENERATE_AND_PLAY_HF(chain_switching_when_out_spent_in_alt_chain_ref_id, "3-*");
// miscellaneous tests

View file

@ -849,7 +849,7 @@ bool pos_wallet_big_block_test::c1(currency::core& c, size_t ev_index, const std
pos_altblocks_validation::pos_altblocks_validation()
{
test_chain_unit_base::set_hardforks_for_old_tests();
//test_chain_unit_base::set_hardforks_for_old_tests();
}
bool pos_altblocks_validation::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
@ -871,23 +871,26 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
std::list<account_base> 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<currency::tx_out_bare>(stake_tx.vout[i]).amount >boost::get<currency::tx_out_bare>( 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<currency::tx_out_bare>(stake_tx.vout[i]).amount > boost::get<currency::tx_out_bare>( 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<test_event_entry>& 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<test_event_entry>& 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<transaction>()), 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<zarcanum_sig>(blk_3aa.miner_tx.signatures[0]).y0.m_u64[1] = 5; // invalidate signature
else
boost::get<NLSAG_sig>(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<test_event_entry>& 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<transaction>()), 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