From 8cc4e99199a4d6e61101854bf9387460fbadaef6 Mon Sep 17 00:00:00 2001 From: sowle Date: Mon, 9 Dec 2024 15:52:07 +0100 Subject: [PATCH 01/10] gui: is_remnotenode_mode_preconfigured() implemented --- src/gui/qt-daemon/application/mainwindow.cpp | 7 ++++++- src/wallet/wallets_manager.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 950c93af..30ca6bc8 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -959,7 +959,12 @@ bool MainWindow::init_backend(int argc, char* argv[]) QString MainWindow::is_remnotenode_mode_preconfigured(const QString& param) { TRY_ENTRY(); - return API_RETURN_CODE_FALSE; + view::api_response ar{}; + if (m_backend.is_remote_node_mode()) + ar.error_code = API_RETURN_CODE_TRUE; + else + ar.error_code = API_RETURN_CODE_FALSE; + return MAKE_RESPONSE(ar); CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 4e7f73a0..1a804726 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -178,6 +178,7 @@ public: std::string add_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor); std::string delete_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id); bool is_core_initialized() { return m_core_initialized;} + bool is_remote_node_mode() const { return m_remote_node_mode; } private: void main_worker(const po::variables_map& vm); From 11b89333451680019b7c79a136fab8fd799db604 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Mon, 9 Dec 2024 17:53:08 +0300 Subject: [PATCH 02/10] === build number: 369 -> 370 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index d718b1b6..cfdeffea 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "1" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 369 +#define PROJECT_VERSION_BUILD_NO 370 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" From 9e3ece181842ebe1c51ed06b5d6f6c2300b57494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= <63650851+stepan-dolgorukov@users.noreply.github.com> Date: Mon, 9 Dec 2024 21:32:41 +0500 Subject: [PATCH 03/10] coretests: implemented the test "block_with_correct_prev_id_on_wrong_height" (#479) --- tests/core_tests/block_validation.cpp | 39 ++++++++++++++++++++++++++- tests/core_tests/block_validation.h | 10 +++++++ tests/core_tests/chaingen_main.cpp | 1 + 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index e2890f37..c5a911a7 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -692,4 +692,41 @@ bool gen_block_wrong_version_agains_hardfork::generate(std::vector& events) const +{ + // Test idea: make sure that a block with correct previous block identifier that is at the wrong height won't be accepted by the core. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_TX(events, tx_0, miner, miner, MK_TEST_COINS(2), blk_0r); + MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner); + m_blk_2.prev_id = currency::get_block_hash(blk_1); + m_blk_2.miner_tx = blk_0r.miner_tx; + m_blk_2.major_version = blk_0r.major_version; + // blk_1 is the previous for blk_2, but height(blk_2) < height(blk_1). + CHECK_AND_ASSERT_EQ(currency::get_block_height(blk_1), 11); + CHECK_AND_ASSERT_EQ(currency::get_block_height(m_blk_2), 10); + DO_CALLBACK(events, "assert_blk_2_has_wrong_height"); + + return true; +} + +bool block_with_correct_prev_id_on_wrong_height::assert_blk_2_has_wrong_height(currency::core& c, [[maybe_unused]] size_t ev_index, [[maybe_unused]] const std::vector& events) const +{ + currency::block_verification_context context_blk_2{}; + + CHECK_AND_ASSERT_EQ(boost::get(m_blk_2.miner_tx.vin.front()).height, 10); + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().add_new_block(m_blk_2, context_blk_2), false); + + return true; +} diff --git a/tests/core_tests/block_validation.h b/tests/core_tests/block_validation.h index f21463ca..7c56f206 100644 --- a/tests/core_tests/block_validation.h +++ b/tests/core_tests/block_validation.h @@ -187,3 +187,13 @@ struct gen_block_invalid_binary_format : public test_chain_unit_base private: size_t m_corrupt_blocks_begin_idx; }; + +struct block_with_correct_prev_id_on_wrong_height : public gen_block_verification_base<1 + CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3> +{ + block_with_correct_prev_id_on_wrong_height(); + bool generate(std::vector& events) const; + bool assert_blk_2_has_wrong_height(currency::core& c, size_t ev_index, const std::vector& events) const; + +private: + mutable currency::block m_blk_2{}; +}; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index d1a217c6..1e98aba1 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1177,6 +1177,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(gen_block_unlock_time_is_timestamp_in_future, "0,3"); GENERATE_AND_PLAY_HF(gen_block_height_is_low, "0,3"); GENERATE_AND_PLAY_HF(gen_block_height_is_high, "0,3"); + GENERATE_AND_PLAY_HF(block_with_correct_prev_id_on_wrong_height, "3-*"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_tx_gen_in, "0,3"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_in, "0,3"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_with_txin_to_key, "0,3"); From 18c17e48b1ae67922873aa556418cd048e8c86c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= <63650851+stepan-dolgorukov@users.noreply.github.com> Date: Mon, 9 Dec 2024 21:34:28 +0500 Subject: [PATCH 04/10] coretests: implemented test "input_refers_to_incompatible_by_type_output" (#480) --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/tx_validation.cpp | 478 +++++++++++++++++++++++++++++ tests/core_tests/tx_validation.h | 10 + 3 files changed, 489 insertions(+) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 1e98aba1..89d6a5b9 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1222,6 +1222,7 @@ int main(int argc, char* argv[]) /* To execute the check of bare balance (function "check_tx_bare_balance") we need to run the test "tx_pool_semantic_validation" on the HF 3. By default behaviour bare outputs are disallowed on the heights >= 10. */ GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); + GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output); // 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 14b3db62..dea895ea 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -2121,3 +2121,481 @@ bool tx_pool_semantic_validation::generate(std::vector& events return true; } + +input_refers_to_incompatible_by_type_output::input_refers_to_incompatible_by_type_output() +{ + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_to_key_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_to_key_input_refers_zarcanum_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_zarcanum_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_zc_input_refers_bare_output_is_wrong); + m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 14); +} + +bool input_refers_to_incompatible_by_type_output::generate(std::vector& events) const +{ + // Test idea: ensure that input and output compatibility checks work. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS(events, blk_0r, blk_0, miner); + block& top{blk_0r}; + MAKE_TX_FEE(events, tx_00, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk_1, top, miner, tx_00); + top = blk_1; + } + + // An input of the type "txin_htlc" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + transaction tx_1{}; + + top = blk; + + { + txin_htlc input{}; + + { + ref_by_id reference{}; + + reference.tx_id = get_transaction_hash(tx_0); + reference.n = get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7)); + CHECK_AND_ASSERT_NEQ(reference.n, UINT64_MAX); + input.key_offsets.push_back(reference); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + } + + input.k_image = crypto::point_t{{0x59, 0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63, + 0x64, 0x3b, 0x3b, 0x47, 0x30}}.to_key_image(); + input.amount = MK_TEST_COINS(7); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + { + tx_out_bare output_bare{}; + txout_to_key output_to_key{}; + + output_bare.amount = MK_TEST_COINS(2); + output_to_key.key = crypto::point_t{{0x2c, 0xdc, 0xc4, 0x7c, 0x38, 0x69, 0xe5, 0xe2, 0x4c, 0x5e, 0x10, 0xb2, 0xbe, 0x57, 0xe9, 0x42, 0x72, 0xd8, 0xf8, 0xb5, 0x97, 0xb9, 0x02, 0x41, 0xba, 0xea, + 0x82, 0xb3, 0xaf, 0x0c, 0xf0, 0x09}}.to_public_key(); + output_bare.target = output_to_key; + tx_1.vout.push_back(output_bare); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 1); + } + + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a global output index to an output with a target of the type "txout_to_key". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + transaction tx_1{}; + + top = blk; + + { + txin_htlc input{}; + + { + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7)), global_output_index), true); + CHECK_AND_ASSERT_NEQ(global_output_index, UINT64_MAX); + input.key_offsets.push_back(global_output_index); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + } + + input.k_image = crypto::point_t{{0xc6, 0x1c, 0xda, 0xf7, 0x9e, 0xb7, 0xd9, 0xc2, 0x46, 0x90, 0x29, 0xc8, 0x8a, 0x8f, 0xb4, 0x3e, 0x8e, 0xa8, 0x3b, 0x33, 0x4c, 0x75, 0xdf, 0xcb, 0x8b, 0x77, 0xf7, + 0x39, 0xa7, 0x17, 0xc9, 0xb4}}.to_key_image(); + input.amount = MK_TEST_COINS(7); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + { + tx_out_bare output_bare{}; + txout_to_key output_to_key{}; + + output_bare.amount = MK_TEST_COINS(2); + output_to_key.key = crypto::point_t{{0xc4, 0x17, 0xc7, 0x7f, 0xb2, 0x5d, 0xcb, 0x4b, 0x29, 0xdf, 0xea, 0x53, 0x70, 0x11, 0xbb, 0x42, 0x33, 0x0d, 0xf1, 0x22, 0x2d, 0xe4, 0x84, 0x24, 0x36, 0xc0, + 0x06, 0xd5, 0x8c, 0xf8, 0x23, 0x62}}.to_public_key(); + output_bare.target = output_to_key; + tx_1.vout.push_back(output_bare); + } + + tx_1.signatures.push_back(NLSAG_sig{{crypto::signature{}}}); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", size_t{ZANO_HARDFORK_04_ZARCANUM}); + + { + REWIND_BLOCKS_N(events, blk, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk; + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_01, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_01); + top = blk; + } + + MAKE_TX_FEE(events, tx_02, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_02); + top = blk; + } + + // An input of the type "txin_to_key" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_to_key input{}; + + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_0), 0}); + CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t({0x59,0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63, + 0x64, 0x3b, 0x3b, 0x47, 0x30}).to_key_image(); + input.amount = MK_TEST_COINS(2); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_to_key" refers by a global output index to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_to_key input{}; + + { + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true); + input.key_offsets.push_back(global_output_index); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c, + 0x92, 0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image(); + // A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0. + input.amount = 0; + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_zc_input" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_zc_input input{}; + + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_00), 0}); + + { + const auto& output{tx_00.vout.at(boost::get(input.key_offsets.front()).n)}; + + CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_bare)); + CHECK_AND_ASSERT_EQ(boost::get(output).target.type(), typeid(txout_to_key)); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_01), 0}); + + { + const auto& output{tx_01.vout.at(boost::get(input.key_offsets.at(1)).n)}; + + CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_zarcanum)); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 2); + input.k_image = crypto::point_t{{0x31, 0x31, 0xd0, 0xf7, 0x13, 0x73, 0xff, 0x21, 0x14, 0xe8, 0x17, 0x4d, 0x18, 0x20, 0x12, 0x2d, 0x80, 0x31, 0xd5, 0x11, 0x82, 0xc0, 0x37, 0xad, 0xd2, 0x7b, 0x8c, + 0xf2, 0xdd, 0xd4, 0x34, 0x9a}}.to_key_image(); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_zc_input_refers_bare_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_htlc input{}; + + input.key_offsets.push_back(ref_by_id{get_transaction_hash(tx_0), 0}); + CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum)); + input.k_image = crypto::point_t{{0x7b, 0xf5, 0x28, 0x09, 0xe8, 0x7e, 0x9c, 0x71, 0x0b, 0xad, 0x24, 0xa1, 0x9d, 0xb4, 0xc8, 0xd7, 0x96, 0x72, 0x18, 0xe6, 0x4b, 0x8f, 0x31, 0x01, 0xb0, 0x43, 0xa0, + 0xcc, 0xce, 0x72, 0x8c, 0x7e}}.to_key_image(); + input.amount = MK_TEST_COINS(2); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a global output index to an output of the type "tx_out_zarcanum". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + + { + REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_htlc input{}; + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true); + input.key_offsets.push_back(global_output_index); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c, 0x92, + 0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image(); + // A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0. + input.amount = 0; + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc)); + + { + uint64_t max_related_block_height{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_to_key)); + + { + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + source_max_unlock_time_for_pos_coinbase), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_zc_input)); + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), true); + } + + { + bool all_inputs_have_explicit_native_asset_id{}; + uint64_t max_related_block_height{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + all_inputs_have_explicit_native_asset_id), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc)); + + { + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + source_max_unlock_time_for_pos_coinbase), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 9888ee3e..6e3ae56e 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -165,3 +165,13 @@ struct tx_pool_semantic_validation : public test_chain_unit_enchanced { bool generate(std::vector& events) const; }; + +struct input_refers_to_incompatible_by_type_output : public test_chain_unit_enchanced +{ + input_refers_to_incompatible_by_type_output(); + bool generate(std::vector& events) const; + bool assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; +}; From 78f622ead1ec1bac665f5f50c267cbed1af33de2 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 10 Dec 2024 21:27:34 +0100 Subject: [PATCH 05/10] bcs: get_block_reward_by_main_chain_height(), get_block_reward_by_hash() implemented; 2) core_rpc_server::fill_block_header_response() now correctly fills 'reward' --- src/currency_core/blockchain_storage.cpp | 51 ++++++++++++++++++++++++ src/currency_core/blockchain_storage.h | 2 + src/rpc/core_rpc_server.cpp | 17 +++++--- src/rpc/core_rpc_server.h | 2 +- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 0d6d41f8..2a6af842 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -973,6 +973,57 @@ bool blockchain_storage::get_block_by_hash(const crypto::hash &h, block &blk) c return false; } +//------------------------------------------------------------------ +bool blockchain_storage::get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX; + + if (height >= m_db_blocks.size()) + return false; + + boost::multiprecision::uint128_t reward_with_fee_mp{}; + if (height != 0) + reward_with_fee_mp = m_db_blocks[height]->already_generated_coins - m_db_blocks[height - 1]->already_generated_coins; + else + reward_with_fee_mp = m_db_blocks[height]->already_generated_coins; + + if (reward_with_fee_mp > amount_max_mp) + return false; + + reward_with_fee = reward_with_fee_mp.convert_to(); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX; + + block_extended_info bei{}; + if (!get_block_extended_info_by_hash(h, bei)) + return false; + + boost::multiprecision::uint128_t reward_with_fee_mp{}; + if (bei.height != 0) + { + block_extended_info bei_prev{}; + if (!get_block_extended_info_by_hash(bei.bl.prev_id, bei_prev)) + return false; + reward_with_fee_mp = bei.already_generated_coins - bei_prev.already_generated_coins; + } + else + { + reward_with_fee_mp = bei.already_generated_coins; + } + + if (reward_with_fee_mp > amount_max_mp) + return false; + + reward_with_fee = reward_with_fee_mp.convert_to(); + return true; +} +//------------------------------------------------------------------ bool blockchain_storage::is_tx_related_to_altblock(crypto::hash tx_id) const { CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 78c75e66..5ebc328c 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -233,6 +233,8 @@ namespace currency size_t get_alternative_blocks_count() const; crypto::hash get_block_id_by_height(uint64_t height) const; bool get_block_by_hash(const crypto::hash &h, block &blk) const; + bool get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const; // only for main chain blocks + bool get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const; // works for main chain and alt chain blocks bool get_block_extended_info_by_height(uint64_t h, block_extended_info &blk) const; bool get_block_extended_info_by_hash(const crypto::hash &h, block_extended_info &blk) const; bool get_block_by_height(uint64_t h, block &blk) const; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 88938641..2cbf9a08 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1156,16 +1156,22 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - uint64_t core_rpc_server::get_block_reward(const block& blk) + uint64_t core_rpc_server::get_block_reward(const block& blk, const crypto::hash& h) { + if (blk.miner_tx.version >= TRANSACTION_VERSION_POST_HF4) + { + uint64_t reward_with_fee = 0; + m_core.get_blockchain_storage().get_block_reward_by_hash(h, reward_with_fee); + return reward_with_fee; + } + + // legacy version, pre HF4 uint64_t reward = 0; BOOST_FOREACH(const auto& out, blk.miner_tx.vout) { VARIANT_SWITCH_BEGIN(out); VARIANT_CASE_CONST(tx_out_bare, out) reward += out.amount; - VARIANT_CASE_CONST(tx_out_zarcanum, out) - //@#@ VARIANT_SWITCH_END(); } return reward; @@ -1173,6 +1179,7 @@ namespace currency //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response) { + crypto::hash block_hash = get_block_hash(blk); response.major_version = blk.major_version; response.minor_version = blk.minor_version; response.timestamp = blk.timestamp; @@ -1181,9 +1188,9 @@ namespace currency response.orphan_status = orphan_status; response.height = get_block_height(blk); response.depth = m_core.get_current_blockchain_size() - response.height - 1; - response.hash = string_tools::pod_to_hex(get_block_hash(blk)); + response.hash = string_tools::pod_to_hex(block_hash); response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to(); - response.reward = get_block_reward(blk); + response.reward = get_block_reward(blk, block_hash); return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index e95f5a41..0e55204b 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -182,7 +182,7 @@ namespace currency bool check_core_ready_(const std::string& calling_method); //utils - uint64_t get_block_reward(const block& blk); + uint64_t get_block_reward(const block& blk, const crypto::hash& h); bool fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response); void set_session_blob(const std::string& session_id, const currency::block& blob); bool get_session_blob(const std::string& session_id, currency::block& blob); From 13ed32d67a89f31e55589384c2d6fc57629b8f74 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 11 Dec 2024 13:56:20 +0100 Subject: [PATCH 06/10] ui update (pr 135) --- src/gui/qt-daemon/layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index f6e3e061..638f98f9 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit f6e3e0611f2100c6d9e76631a9fcfeb60e82d6d6 +Subproject commit 638f98f9e25fa3c2f88338b7efe4b1c45ea0e23c From c0ca49c30ac8d064422a6fa03f9f80fabf2c030e Mon Sep 17 00:00:00 2001 From: zano build machine Date: Wed, 11 Dec 2024 15:58:01 +0300 Subject: [PATCH 07/10] === build number: 370 -> 371 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index cfdeffea..a3b0ca4f 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "1" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 370 +#define PROJECT_VERSION_BUILD_NO 371 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" From eda0472f1e26f8021e26e23c0fc542846f7ecf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= <63650851+stepan-dolgorukov@users.noreply.github.com> Date: Sat, 14 Dec 2024 03:10:34 +0500 Subject: [PATCH 08/10] coretests: implemented a test for the function "blockchain_storage::fill_tx_rpc_inputs" (#486) --- tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/chaingen_tests_list.h | 3 +- tests/core_tests/daemon_rpc.cpp | 573 +++++++++++++++++++++++++ tests/core_tests/daemon_rpc.h | 18 + 4 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 tests/core_tests/daemon_rpc.cpp create mode 100644 tests/core_tests/daemon_rpc.h diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 89d6a5b9..8c4fef66 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1154,6 +1154,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(one_block); GENERATE_AND_PLAY(gen_ring_signature_1); GENERATE_AND_PLAY(gen_ring_signature_2); + GENERATE_AND_PLAY(fill_tx_rpc_inputs); //GENERATE_AND_PLAY(gen_ring_signature_big); // Takes up to XXX hours (if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10) // tests for outputs mixing in diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index abac7b00..e4ca2221 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -45,4 +45,5 @@ #include "multiassets_test.h" #include "ionic_swap_tests.h" #include "attachment_isolation_encryption_test.h" -#include "pos_fuse_test.h" \ No newline at end of file +#include "pos_fuse_test.h" +#include "daemon_rpc.h" diff --git a/tests/core_tests/daemon_rpc.cpp b/tests/core_tests/daemon_rpc.cpp new file mode 100644 index 00000000..f968719e --- /dev/null +++ b/tests/core_tests/daemon_rpc.cpp @@ -0,0 +1,573 @@ +#include "chaingen.h" +#include "daemon_rpc.h" + +fill_tx_rpc_inputs::fill_tx_rpc_inputs() +{ + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c1); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c2); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c3); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c4); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c5); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c6); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c7); + REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c8); +} + +bool fill_tx_rpc_inputs::generate(std::vector& events) const +{ + // Test idea: make sure that the function "blockchain_storage::fill_tx_rpc_inputs" works as expected. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + // A transaction in the default state. + DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(currency::transaction{})); + + // A transaction with an input of the type "txin_to_key" in the default state. + { + currency::transaction tx{}; + + tx.vin.push_back(std::move(currency::txin_to_key{})); + DO_CALLBACK_PARAMS_STR(events, "c2", t_serializable_object_to_blob(tx)); + } + + // A transaction with an input of the type "txin_zc_input". + { + currency::transaction tx{}; + + { + currency::txin_zc_input input{}; + + input.k_image = {}; + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c6", t_serializable_object_to_blob(tx)); + } + + // A transaction with several "txin_to_key" inputs those have different .amount values. + { + currency::transaction tx{}; + + tx.vin.reserve(3); + + { + currency::txin_to_key input{}; + + CHECK_AND_ASSERT_EQ(input.amount, 0); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_to_key input{}; + + input.amount = UINT64_MAX; + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_to_key input{}; + + input.amount = 16730018105294876523ull; + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c3", t_serializable_object_to_blob(tx)); + } + + // A transaction with inputs of all possible types. + { + currency::transaction tx{}; + + tx.vin.reserve(5); + tx.vin.push_back(std::move(currency::txin_gen{})); + tx.vin.push_back(std::move(currency::txin_to_key{})); + tx.vin.push_back(std::move(currency::txin_htlc{})); + + { + currency::txin_zc_input input{}; + + input.k_image = {}; + tx.vin.push_back(std::move(input)); + } + + tx.vin.push_back(std::move(currency::txin_multisig{})); + + DO_CALLBACK_PARAMS_STR(events, "c4", t_serializable_object_to_blob(tx)); + } + + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0); + + // A transaction with inputs of all possible types. + { + currency::transaction tx{}; + + tx.vin.reserve(5); + tx.vin.push_back(std::move(currency::txin_gen{/* .height = */ 7137406440025745250})); + + { + currency::txin_to_key input{}; + + input.key_offsets.push_back(5350230927837587142ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 0u})); + input.amount = 2341818593703234797ull; + input.k_image = crypto::point_t{{0x62, 0xd9, 0xa0, 0xff, 0xb1, 0x89, 0x06, 0xbe, 0xbd, 0xe9, 0xce, 0xd5, 0xc2, 0x04, 0x5b, 0x6b, 0xb4, 0x5f, 0x9c, 0x3b, 0x31, 0xcc, 0x72, 0xc7, 0x55, 0x25, 0x0f, + 0xa2, 0xb2, 0xbf, 0xb1, 0x0c}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 2613407258u, /* .n_extras = */ 347754399u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 5559118977069213037ull, /* .hsh = */ currency::null_hash, /* cnt = */ 8106306627691316520ull})); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_htlc input{}; + + input.key_offsets.push_back(9536097715806449708ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 9u})); + input.amount = 11357119244607763967ull; + input.k_image = crypto::point_t{{0xcb, 0xec, 0xfb, 0x36, 0x02, 0x1c, 0xe5, 0x64, 0xee, 0x6a, 0xb8, 0x67, 0xb2, 0x8e, 0xe9, 0xef, 0x80, 0x17, 0x34, 0x6f, 0xa8, 0x67, 0x3e, 0x45, 0x3a, 0xe0, 0xd4, + 0x8b, 0x1a, 0x13, 0x75, 0xe2}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull})); + input.hltc_origin = "htlc-origin"; + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_zc_input input{}; + + input.key_offsets.push_back(16540286509618649069ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 4})); + input.k_image = crypto::point_t{{0x53, 0xcf, 0xaf, 0x48, 0x4d, 0xf8, 0xfb, 0x09, 0x4c, 0x01, 0x59, 0x9f, 0xe2, 0x2d, 0x3c, 0x23, 0x96, 0x2d, 0x8c, 0x24, 0x09, 0xf9, 0xd3, 0xe6, 0xf3, 0x27, 0xe8, + 0x7c, 0x7a, 0x90, 0x9c, 0xab}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull})); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_multisig input{}; + + input.amount = 14073369620052150183ull; + input.multisig_out_id = crypto::cn_fast_hash("multisig-out-id", 15); + input.sigs_count = 3497547654u; + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 1801772931u, /* .n_extras = */ 167800219u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 12438971857615319230ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 13515222808659969031ull})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c5", t_serializable_object_to_blob(tx)); + } + + /* A wrong reference by an object of the type "ref_by_id": a value of the attribute ".n" representing an offset is greater than a length of a container of outputs.The function "fill_tx_rpc_inputs" + returns false. */ + { + currency::transaction tx{}; + + { + currency::txin_to_key input{}; + + CHECK_AND_ASSERT_GREATER(1968482779, tx_0.vout.size() - 1); + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 1968482779u})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c7", t_serializable_object_to_blob(tx)); + } + + // A wrong reference by an object of the type "ref_by_id": hashcode of non-existent transaction is specified. The function "fill_tx_rpc_inputs" returns false. + { + currency::transaction tx{}; + + { + currency::txin_to_key input{}; + + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::null_hash, 0u})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c8", t_serializable_object_to_blob(tx)); + } + + return true; +} + +bool fill_tx_rpc_inputs::c1(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.empty(), true); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c2(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 1); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c3(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 3); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, UINT64_MAX); + CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.back().amount, 16730018105294876523ull); + CHECK_AND_ASSERT_EQ(info.ins.back().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.back().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.back().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.back().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.back().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c4(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 5); + + for (size_t position{}; position < info.ins.size(); ++position) + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(position).multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(position).htlc_origin.empty(), true); + + if (position == 0) + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id.empty(), true); + } + + else + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(position).global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(position).etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c5(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 5); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, 2341818593703234797ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, "8172e80b8da3bcbce2ee7df42466627bb3559b80bb504f1fd56b460eedbc2ce9"); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.front(), 5350230927837587142ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.front(), "n_outs: 2613407258, n_extras: 347754399"); + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.back(), "cnt: 8106306627691316520, sz: 5559118977069213037, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).amount, 11357119244607763967ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).htlc_origin, epee::string_tools::buff_to_hex_nodelimer(std::string{"htlc-origin"})); + CHECK_AND_ASSERT_EQ(info.ins.at(2).kimage_or_ms_id, "f15201980333d6ca8fda90c73814baea0864eb56597e40c38061ec77644585ea"); + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.front(), 9536097715806449708ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888"); + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).amount, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(3).kimage_or_ms_id, "c08b36a7f77185f31a570a7f51aa550122026985e5de7941218510a1e973202e"); + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.front(), 16540286509618649069ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888"); + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(4).amount, 14073369620052150183ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(4).kimage_or_ms_id, "aacdff6018af0aae84d7a836a7f0b4309b51a28bfc4f566657c67b903a3ccba5"); + CHECK_AND_ASSERT_EQ(info.ins.at(4).global_indexes.size(), 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.front(), "n_outs: 1801772931, n_extras: 167800219"); + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.back(), "cnt: 13515222808659969031, sz: 12438971857615319230, hsh: " + std::string(64, '0')); + } + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c6(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 1); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c7(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.size(), 1); + + { + const auto& input{boost::get(tx.vin.front())}; + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + + { + const auto& reference{boost::get(input.key_offsets.front())}; + + CHECK_AND_ASSERT_EQ(reference.n, 1968482779u); + + { + const auto pointer_entry{core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id)}; + + CHECK_AND_ASSERT_NEQ(pointer_entry, nullptr); + CHECK_AND_ASSERT(reference.n >= pointer_entry->m_global_output_indexes.size(), false); + } + } + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false); + + return true; +} + +bool fill_tx_rpc_inputs::c8(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.size(), 1); + + { + const auto& input{boost::get(tx.vin.front())}; + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + + { + const auto& reference{boost::get(input.key_offsets.front())}; + + CHECK_AND_ASSERT_EQ(reference.tx_id, currency::null_hash); + CHECK_AND_ASSERT_EQ(reference.n, 0u); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id), nullptr); + } + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false); + + return true; +} diff --git a/tests/core_tests/daemon_rpc.h b/tests/core_tests/daemon_rpc.h new file mode 100644 index 00000000..75efa31b --- /dev/null +++ b/tests/core_tests/daemon_rpc.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "chaingen.h" + +struct fill_tx_rpc_inputs : public test_chain_unit_enchanced +{ + fill_tx_rpc_inputs(); + bool generate(std::vector& events) const; + bool c1(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c2(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c3(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c4(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c5(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c6(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c7(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c8(const currency::core& core, const size_t event_position, const std::vector& events) const; +}; From 7b527483c2f42b1852846a8c1800768063240859 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 24 Dec 2024 20:58:58 +0100 Subject: [PATCH 09/10] wallet rpc: getbalance now returns brief utxo stat for each asset --- src/wallet/wallet2.cpp | 4 ++++ src/wallet/wallet_public_structs_defs.h | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5ab899dd..ac486389 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3756,6 +3756,10 @@ bool wallet2::balance(std::unordered_map Date: Tue, 24 Dec 2024 23:49:18 +0300 Subject: [PATCH 10/10] === build number: 371 -> 372 === --- src/version.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h.in b/src/version.h.in index a3b0ca4f..9b2e4cac 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "1" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 371 +#define PROJECT_VERSION_BUILD_NO 372 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"