diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 801aa2f8..fc670958 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1229,6 +1229,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output); GENERATE_AND_PLAY_HF(tx_pool_validation_and_chain_switch, "4-*"); + GENERATE_AND_PLAY_HF(tx_coinbase_separate_sig_flag, "4-*"); GENERATE_AND_PLAY(tx_input_mixins); // Double spend diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 20ada534..78bc9fa3 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -2729,6 +2729,42 @@ bool tx_pool_validation_and_chain_switch::c1(currency::core& c, size_t ev_index, return true; } +// Сoinbase transactions must NOT allow the TX_FLAG_SIGNATURE_MODE_SEPARATE flag. +// Сhecks that setting this flag for coinbase fails, while a default coinbase (without the flag) succeeds. +bool tx_coinbase_separate_sig_flag::generate(std::vector& events) const +{ + GENERATE_ACCOUNT(miner); + + uint64_t ts = test_core_time::get_time(); + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts); + DO_CALLBACK(events, "configure_core"); + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); + + block blk_2; + auto coinbase_default_cb = [](transaction& miner_tx, const keypair&) -> bool { return true; }; + auto coinbase_separate_cb = [](transaction& miner_tx, const keypair&) -> bool + { + set_tx_flags(miner_tx, get_tx_flags(miner_tx) | TX_FLAG_SIGNATURE_MODE_SEPARATE); + return true; + }; + + // сonstruct a block with the forbidden flag, should fail after hf4 + bool with_separate_flag = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_separate_cb, blk_2); + CHECK_AND_ASSERT_MES(with_separate_flag, false, "expected failure because TX_FLAG_SIGNATURE_MODE_SEPARATE is forbidden for coinbase after HF4"); + + DO_CALLBACK(events, "mark_invalid_block"); + events.push_back(blk_2); + + // construct a default coinbase block, should succeed + bool default_tx = generator.construct_block_gentime_with_coinbase_cb(blk_1r, miner, coinbase_default_cb, blk_2); + CHECK_AND_ASSERT_MES(default_tx, true, "default coinbase must succeed"); + + events.push_back(blk_2); + + return true; +} + tx_input_mixins::tx_input_mixins() { REGISTER_CALLBACK_METHOD(tx_input_mixins, configure_core); diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 5eeea597..5a68d81d 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -184,6 +184,11 @@ struct tx_pool_validation_and_chain_switch : public wallet_test bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; +struct tx_coinbase_separate_sig_flag : public test_chain_unit_enchanced +{ + bool generate(std::vector& events) const; +}; + struct tx_input_mixins: public test_chain_unit_enchanced { tx_input_mixins();