From e9bc068bfb64b4fcbade957084849bffffc1b0b5 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 16 Oct 2019 16:34:34 +0300 Subject: [PATCH] coretests: tx_key_image_pool_conflict test added --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/tx_validation.cpp | 125 +++++++++++++++++++++++++++++ tests/core_tests/tx_validation.h | 10 +++ 3 files changed, 136 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 42f8f112..230cf874 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -919,6 +919,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(tx_expiration_time); GENERATE_AND_PLAY(tx_expiration_time_and_block_template); GENERATE_AND_PLAY(tx_expiration_time_and_chain_switching); + GENERATE_AND_PLAY(tx_key_image_pool_conflict); // Double spend GENERATE_AND_PLAY(gen_double_spend_in_tx); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 5c6c91c6..a71dae24 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1450,3 +1450,128 @@ bool tx_expiration_time_and_chain_switching::generate(std::vector& events) const +{ + bool r = false; + + m_miner_acc.generate(); + GENERATE_ACCOUNT(bob_acc); + MAKE_GENESIS_BLOCK(events, blk_0, m_miner_acc, test_core_time::get_time()); + + REWIND_BLOCKS_N(events, blk_0r, blk_0, m_miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + // make tx_0 : miner -> bob + std::vector sources; + std::vector destinations; + r = fill_tx_sources_and_destinations(events, blk_0r, m_miner_acc.get_keys(), bob_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); + CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); + transaction tx_0 = AUTO_VAL_INIT(tx_0); + r = construct_tx(m_miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, 0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + LOG_PRINT_YELLOW("tx_0 = " << get_transaction_hash(tx_0), LOG_LEVEL_0); + // do not push tx_0 into events yet + + // tx_1 spends the same key image as tx_0 + transaction tx_1 = tx_0; + keypair kp = keypair::generate(); + // change tx pub key to end up with different tx hash + update_or_add_field_to_extra(tx_1.extra, kp.pub); + r = resign_tx(m_miner_acc.get_keys(), sources, tx_1); + CHECK_AND_ASSERT_MES(r, false, "resign_tx failed"); + LOG_PRINT_YELLOW("tx_1 = " << get_transaction_hash(tx_1), LOG_LEVEL_0); + + // tx_2 spends the same key image as tx_0 + transaction tx_2 = tx_0; + kp = keypair::generate(); + // change tx pub key to end up with different tx hash + update_or_add_field_to_extra(tx_2.extra, kp.pub); + r = resign_tx(m_miner_acc.get_keys(), sources, tx_2); + CHECK_AND_ASSERT_MES(r, false, "resign_tx failed"); + LOG_PRINT_YELLOW("tx_2 = " << get_transaction_hash(tx_2), LOG_LEVEL_0); + + events.push_back(tx_1); + + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(1)); + + // as long as tx_0 is using the same key image as tx_1, tx_0 and tx_2 can't be added to the pool atm + // make sure that it's true + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx_0); + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx_2); + + // however, tx_0 and tx_2 can be added with kept_by_block flag (to simulate it's going with blk_1) + events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); + events.push_back(tx_0); + events.push_back(tx_2); + events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false)); + + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(3)); + + // make a block with tx_0 and put tx_0 to the blockchain + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, m_miner_acc, tx_0); + + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + // tx_1 and tx_2 is still in the pool + // it can never be added to any block as long as blk_1 is in the blockchain due to key image conflict + + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_2_bad, blk_1, m_miner_acc, tx_1); + + // add tx_1 to alt block, it should go well + MAKE_NEXT_BLOCK_TX1(events, blk_1a, blk_0r, m_miner_acc, tx_1); + + // however, it does not remove tx from the pool + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + MAKE_NEXT_BLOCK(events, blk_2, blk_1, m_miner_acc); + + DO_CALLBACK(events, "remove_stuck_txs"); + + // remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(2)); + + // shift time by CURRENCY_MEMPOOL_TX_LIVETIME + events.push_back(event_core_time(CURRENCY_MEMPOOL_TX_LIVETIME + 1, true)); + + // remove_stuck_txs should remove only tx_2 and left tx_1 + DO_CALLBACK(events, "remove_stuck_txs"); + + DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast(1)); + + DO_CALLBACK(events, "print_tx_pool"); + + return true; +} + +bool tx_key_image_pool_conflict::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false; + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count()); + + // try to mine a block and make sure tx_1 is still in the pool (was not added to the blocktemplate) + block b; + r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &b); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + + // make sure tx_1 is still here + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "incorrect tx pool count = " << c.get_pool_transactions_count()); + + return true; +} + +bool tx_key_image_pool_conflict::c2(currency::core& c, size_t ev_index, const std::vector& events) +{ + return true; +} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 6996f3de..5c8bb524 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -147,3 +147,13 @@ struct tx_expiration_time_and_chain_switching : public test_chain_unit_enchanced { bool generate(std::vector& events) const; }; + +struct tx_key_image_pool_conflict : public test_chain_unit_enchanced +{ + tx_key_image_pool_conflict(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); + bool c2(currency::core& c, size_t ev_index, const std::vector& events); + + mutable currency::account_base m_miner_acc; +};