From 0d3e90f4a544362695881afac33cdc22acee762a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= Date: Tue, 3 Sep 2024 00:26:39 +0500 Subject: [PATCH 01/15] coretests: asset_operation_and_hardfork_checks test added --- tests/core_tests/multiassets_test.cpp | 320 ++++++++++++++++++++++++++ tests/core_tests/multiassets_test.h | 21 ++ 2 files changed, 341 insertions(+) diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 94a938d2..82834a9e 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -887,3 +887,323 @@ bool asset_emission_and_unconfirmed_balance::c1(currency::core& c, size_t ev_ind return true; } + +//------------------------------------------------------------------------------ + +asset_operation_and_hardfork_checks::asset_operation_and_hardfork_checks() +{ + m_adb_hello.total_max_supply = 1'000'000'000'000'000'000; + m_adb_hello.current_supply = 1'000'000'000'000'000'000; + m_adb_hello.ticker = "HLO"; + m_adb_hello.full_name = "HELLO_WORLD"; + m_adb_hello.meta_info = "Hello, world!"; + m_adb_hello.hidden_supply = false; + + m_ado_hello.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; + m_ado_hello.opt_asset_id = currency::null_pkey; + + m_adb_bye.total_max_supply = 1'000'000'000'000'000'000; + m_adb_bye.current_supply = 1'000'000'000'000'000'000; + m_adb_bye.ticker = "BYE"; + m_adb_bye.full_name = "BYE_WORLD"; + m_adb_bye.meta_info = "Bye, world!"; + m_adb_bye.hidden_supply = false; + + m_ado_bye.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; + m_ado_hello.opt_asset_id = currency::null_pkey; + + REGISTER_CALLBACK_METHOD(asset_operation_and_hardfork_checks, c1); + REGISTER_CALLBACK_METHOD(asset_operation_and_hardfork_checks, c2); +} + +bool asset_operation_and_hardfork_checks::generate( + std::vector& events) const +{ + /* + 0 10 11 21 22 + ( 0) - ... - (0r) - ( 1) - ... - (1r) - ( 2) + \ \ + [tx_0] [tx_1] + */ + + bool success{false}; + std::vector sources{}; + std::vector destinations{}; + transaction tx_0{}, tx_1{}, tx_2{}, tx_3{}, tx_4{}; + uint64_t tx_version{}; + crypto::secret_key stub{}; + + m_accounts.resize(2); + account_base& miner{m_accounts[MINER_ACC_IDX]}; + miner.generate(); + account_base& alice{m_accounts[ALICE_ACC_IDX]}; + alice.generate(); + + m_adb_hello.owner = alice.get_public_address().spend_public_key; + m_ado_hello.descriptor = m_adb_hello; + + m_adb_bye.owner = alice.get_public_address().spend_public_key; + m_ado_bye.descriptor = m_adb_bye; + + MAKE_GENESIS_BLOCK(events, + blk_0, + miner, + test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS_N_WITH_TIME(events, + blk_0r, + blk_0, + miner, + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + success = fill_tx_sources_and_destinations(events, + /* head = */ blk_0r, + /* from = */ miner.get_keys(), + /* to = */ alice.get_public_address(), + /* amount = */ MK_TEST_COINS(12), + /* fee = */ TESTS_DEFAULT_FEE, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + tx_version = get_tx_version(get_block_height(blk_0r), + m_hardforks); + + success = construct_tx(miner.get_keys(), + sources, + destinations, + empty_attachment, + tx_0, + tx_version, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0"); + + ADD_CUSTOM_EVENT(events, tx_0); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0); + + REWIND_BLOCKS_N_WITH_TIME(events, + blk_1r, + blk_1, + miner, + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + sources.clear(); + destinations.clear(); + + success = fill_tx_sources_and_destinations(events, + /* head = */ blk_1r, + /* from = */ alice, + /* to = */ alice, + /* amount = */ MK_TEST_COINS(5), + /* fee = */ TESTS_DEFAULT_FEE, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + destinations.emplace_back(/* amount = */ 1'000'000'000'000'000'000, + /* to = */ alice.get_public_address(), + /* asset_id = */ currency::null_pkey); + + tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); + + success = construct_tx(alice.get_keys(), + sources, + destinations, + /* extra = */ {m_ado_hello}, + empty_attachment, + tx_1, + tx_version, + stub, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_1"); + ADD_CUSTOM_EVENT(events, tx_1); + + MAKE_NEXT_BLOCK_TX1(events, + blk_2, + blk_1r, + alice, + tx_1); + + REWIND_BLOCKS_N_WITH_TIME(events, + blk_2r, + blk_2, + miner, + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + /* A transaction that has at least 2 registration operation descriptors in its + extra is rejected by the core. */ + + sources.clear(); + destinations.clear(); + + success = fill_tx_sources_and_destinations(events, + /* head = */ blk_2r, + /* from = */ alice, + /* to = */ alice, + /* amount = */ MK_TEST_COINS(2), + /* fee = */ TESTS_DEFAULT_FEE, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + tx_version = get_tx_version(get_block_height(blk_2r), + m_hardforks); + + success = construct_tx(alice.get_keys(), + sources, + destinations, + /* extra = */ {m_ado_hello, m_ado_hello}, + empty_attachment, + tx_2, + tx_version, + stub, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_2"); + + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_2); + + sources.clear(); + destinations.clear(); + + /* A transaction that contains a registration operation descriptor in its + attachement, but extra is empty, is valid, but doesn't register the asset. The + fact that the asset is not registered is checked in the assertions in the + callback с2. */ + + success = fill_tx_sources_and_destinations(events, + /* head = */ blk_2r, + /* from = */ alice, + /* to = */ alice, + /* amount = */ MK_TEST_COINS(2), + /* fee = */ TESTS_DEFAULT_FEE, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + tx_version = get_tx_version(get_block_height(blk_2r), + m_hardforks); + + success = construct_tx(alice.get_keys(), + sources, + destinations, + /* attachments = */ {m_ado_bye}, + tx_3, + tx_version, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_3"); + + ADD_CUSTOM_EVENT(events, tx_3); + DO_CALLBACK(events, "c2"); + + sources.clear(); + destinations.clear(); + + /* A transaction that contains a registration operation descriptor in its + attachement, but extra is empty, is valid, but doesn't register the asset. In + this case a different definition of the function construct_tx is used. */ + + success = fill_tx_sources_and_destinations(events, + /* head = */ blk_2r, + /* from = */ alice, + /* to = */ alice, + /* amount = */ MK_TEST_COINS(2), + /* fee = */ TESTS_DEFAULT_FEE, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + tx_version = get_tx_version(get_block_height(blk_2r), + m_hardforks); + + success = construct_tx(alice.get_keys(), + sources, + destinations, + empty_extra, + /* attachments = */ {m_ado_bye}, + tx_4, + tx_version, + stub, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_4"); + + ADD_CUSTOM_EVENT(events, tx_4); + DO_CALLBACK(events, "c2"); + DO_CALLBACK(events, "c1"); + + return true; +} + +bool asset_operation_and_hardfork_checks::c1( + currency::core& c, + size_t ev_index, + const std::vector& events) +{ + std::shared_ptr wallet{ + init_playtime_test_wallet_t(events, c, ALICE_ACC_IDX) + }; + + wallet->refresh(); + + crypto::point_t asset_id_point{}; + crypto::public_key asset_id_public_key{}; + currency::get_or_calculate_asset_id(m_ado_hello, + &asset_id_point, + &asset_id_public_key); + + CHECK_AND_ASSERT_MES( + check_balance_via_wallet(*wallet, + /* name = */ "Alice", + /* expected_total = */ 1'000'000'000'000'000'000, + /* expected_mined = */ 0, + /* expected_unlocked = */ 1'000'000'000'000'000'000, + /* expected_awaiting_in = */ INVALID_BALANCE_VAL, + /* expected_awaiting_out = */ INVALID_BALANCE_VAL, + asset_id_public_key), + false, + "balance check failed"); + + return true; +} + +bool asset_operation_and_hardfork_checks::c2( + currency::core& c, + size_t ev_index, + const std::vector& events) +{ + crypto::point_t asset_id_pt{}; + crypto::public_key asset_id{}; + currency::asset_descriptor_base stub{}; + + CHECK_AND_ASSERT_MES( + get_or_calculate_asset_id(m_ado_bye, + &asset_id_pt, + &asset_id), + false, + "fail to calculate asset id"); + + CHECK_AND_ASSERT_MES( + !c.get_blockchain_storage().get_asset_info(asset_id, + stub), + false, + "unregistered asset has info"); + + return true; +} diff --git a/tests/core_tests/multiassets_test.h b/tests/core_tests/multiassets_test.h index bb2fdacc..ce844292 100644 --- a/tests/core_tests/multiassets_test.h +++ b/tests/core_tests/multiassets_test.h @@ -47,3 +47,24 @@ struct asset_emission_and_unconfirmed_balance : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct asset_operation_and_hardfork_checks : public wallet_test +{ + public: + asset_operation_and_hardfork_checks(); + + 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); + + private: + mutable currency::asset_descriptor_base m_adb_hello{}; + mutable currency::asset_descriptor_operation m_ado_hello{}; + mutable currency::asset_descriptor_base m_adb_bye{}; + mutable currency::asset_descriptor_operation m_ado_bye{}; +}; From d74a04d6df33804fe1d5162de76415ab9db1fa3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= Date: Fri, 6 Sep 2024 16:57:14 +0500 Subject: [PATCH 02/15] coretests: asset_operation_and_hardfork_checks test added * Implement "asset_operation_and_hardfork_checks" test * Run "asset_operation_and_hardfork_checks" test on core tests run --- tests/core_tests/chaingen_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index d31857a2..eaff24a3 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1297,7 +1297,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(attachment_isolation_test, "4-*"); - + GENERATE_AND_PLAY_HF(asset_operation_and_hardfork_checks, "4-*"); // GENERATE_AND_PLAY(gen_block_reward); // END OF TESTS */ From dc76fb9051d90cbccb30c2c62150b4f7b6b0ce4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= Date: Sat, 7 Sep 2024 05:12:44 +0500 Subject: [PATCH 03/15] unit_tests: fixes for multiassets.get_or_calculate_asset_id_* * Create multiassets test * Correct an indentation * Remove unnecessary assertions in cases of ASSET_DESCRIPTOR_OPERATION_UNDEFINED * Correctly specify a string that represents the serialized object --- tests/unit_tests/multiassets_test.cpp | 36 ++++++++------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/tests/unit_tests/multiassets_test.cpp b/tests/unit_tests/multiassets_test.cpp index 4d677aab..a996acad 100644 --- a/tests/unit_tests/multiassets_test.cpp +++ b/tests/unit_tests/multiassets_test.cpp @@ -399,7 +399,7 @@ TEST(multiassets, get_or_calculate_asset_id_public_burn) TEST(multiassets, get_or_calculate_asset_id_undefined) { - bool success{false}; + bool success{false}; crypto::point_t pt_public_key{}; success = pt_public_key.from_string( @@ -448,8 +448,6 @@ TEST(multiassets, get_or_calculate_asset_id_undefined) &calculated_asset_id_key); ASSERT_FALSE(success); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); } TEST(multiassets, get_or_calculate_asset_id_register_serialization) @@ -680,18 +678,6 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_serialization) &calculated_asset_id_pt, &calculated_asset_id_key); ASSERT_FALSE(success); - - const std::string expected_asset_id_str{ - "979eb706ace2eb83f9125658b23fb352208480cb3b90c43e2df0d298f9754ebc"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); } TEST(multiassets, get_or_calculate_asset_id_register_boost_serialization) @@ -940,7 +926,7 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_boost_serialization) 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x04', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', @@ -949,20 +935,20 @@ TEST(multiassets, get_or_calculate_asset_id_undefined_boost_serialization) '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '@', '\x8c', - '\xf8', '\xb7', '\xfb', '\x80', '\x8f', '@', 'Y', '=', 'n', - '\xb7', 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7', - '\x01', 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';', - '\xe0', '`', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xe9', '\x1b', '\x9a', + 's', ')', '-', 'n', '\xa4', 'o', '\xb3', '\xd4', '\xf4', + '\xcc', 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6', + '\x84', '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5', + '\x1c', '\x16', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', 'T', '\xf3', '\xf7', ',', 'r', '\xe5', - '\xb0', '\x14', '\xad', '+', '+', '\x90', '\x01', '\xac', '\xef', - '\x95', 'O', '\xe8', '-', '\xd3', '\xed', 'V', '\xa3', '\x8c', - '\xd9', '\xdd', '\xc5', '\xdb', 'W', 'g', '?', '\x8f'}; + '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', + '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', + 'R', ' ', '\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>', + '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'}; success = tools::unserialize_obj_from_buff( asset_descriptor_operation, From 8904cc20c4da3ba911a298c798ac9008cc13d1d4 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 10 Sep 2024 18:23:39 +0400 Subject: [PATCH 04/15] fixed serialization test --- tests/unit_tests/serialization.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 47e0d4c4..bd53b009 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -757,30 +757,30 @@ struct A struct A_v1 : public A { std::vector vector_two; - + uint8_t current_version = 1; BEGIN_SERIALIZE() FIELD(one) FIELD(two) FIELD(vector_one) - VERSION(1) - if (s_version < 1) return true; + VERSION_TO_MEMBER(1, current_version) FIELD(vector_two) END_SERIALIZE() }; + struct A_v2 : public A_v1 { std::vector vector_3; std::vector vector_4; - + uint8_t current_version = 2; BEGIN_SERIALIZE() //CURRENT_VERSION(2) FIELD(one) FIELD(two) FIELD(vector_one) - VERSION(2) + VERSION_TO_MEMBER(2, current_version) if (s_version < 1) return true; FIELD(vector_two) if (s_version < 2) return true; @@ -792,13 +792,14 @@ struct A_v2 : public A_v1 struct A_v3 : public A_v2 { std::vector vector_5; + uint8_t current_version = 3; BEGIN_SERIALIZE() //CURRENT_VERSION(3) FIELD(one) FIELD(two) FIELD(vector_one) - VERSION(3) + VERSION_TO_MEMBER(3, current_version) if (s_version < 1) return true; FIELD(vector_two) if (s_version < 2) return true; From ab73f0d19f943e4aa5b7eed5b9887b86a082b2a8 Mon Sep 17 00:00:00 2001 From: sowle Date: Wed, 11 Sep 2024 22:36:54 +0200 Subject: [PATCH 05/15] coretests: asset_operation_and_hardfork_checks test fixed --- tests/core_tests/multiassets_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 82834a9e..12cabc51 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -1172,7 +1172,7 @@ bool asset_operation_and_hardfork_checks::c1( check_balance_via_wallet(*wallet, /* name = */ "Alice", /* expected_total = */ 1'000'000'000'000'000'000, - /* expected_mined = */ 0, + /* expected_mined = */ 2 * COIN, /* expected_unlocked = */ 1'000'000'000'000'000'000, /* expected_awaiting_in = */ INVALID_BALANCE_VAL, /* expected_awaiting_out = */ INVALID_BALANCE_VAL, From 7fbfec3441048cf946f973bb77a6e5fe5b75a2d8 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 12 Sep 2024 02:39:20 +0200 Subject: [PATCH 06/15] minor improvements (now unit_tests should be autoexecuted each commit) --- src/currency_core/currency_format_utils.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index f2ed06d4..e9ef0eee 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -116,7 +116,7 @@ namespace currency secret_index = ring.size() - 1; } - CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs, asset id: " << H); + CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": cannot find a corresponding asset id in inputs or asset operations; asset id: " << H); result.bge_proofs.emplace_back(crypto::BGE_proof_s{}); uint8_t err = 0; @@ -322,7 +322,7 @@ namespace currency CHECK_AND_ASSERT_MES(ogc.asset_id_blinding_mask_x_amount_sum.is_zero(), false, "it's expected that all asset ids for this tx are obvious and thus explicit"); // because this tx has no ZC inputs => all outs clearly have native asset id CHECK_AND_ASSERT_MES(ogc.ao_amount_blinding_mask.is_zero(), false, "asset emmission is not allowed for txs without ZC inputs"); - // (sum(bare inputs' amounts) - fee) * H + sum(pseudo out amount commitments) - sum(outputs' commitments) = lin(G) + // (sum(bare inputs' amounts) - fee) * H - sum(outputs' commitments) = lin(G) crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt - ogc.amount_commitments_sum; crypto::scalar_t secret_x = -ogc.amount_blinding_masks_sum; @@ -336,6 +336,8 @@ namespace currency { // there're ZC inputs => in main balance equation we only need to cancel out X-component, because G-component cancelled out by choosing blinding mask for the last pseudo out amount commitment + // (sum(bare inputs' amounts) - fee) * H + sum(pseudo out amount commitments) + asset_op_commitment - sum(outputs' commitments) = lin(X) + crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt + ogc.pseudo_out_amount_commitments_sum + (ogc.ao_commitment_in_outputs ? -ogc.ao_amount_commitment : ogc.ao_amount_commitment) - ogc.amount_commitments_sum; crypto::scalar_t secret_x = ogc.real_in_asset_id_blinding_mask_x_amount_sum - ogc.asset_id_blinding_mask_x_amount_sum; From d083f54edd84dd3c87296036b3f26301626be011 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 12 Sep 2024 06:09:23 +0200 Subject: [PATCH 07/15] gui update --- 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 65fb3594..6d212d4e 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 65fb3594d1930d943c029b103a2de43fae498452 +Subproject commit 6d212d4eefaf6d13c72799cb89be2c80b1813d38 From 41ef9caf409a9ec6a7c0cc9a4756903ed12a702f Mon Sep 17 00:00:00 2001 From: zano build machine Date: Thu, 12 Sep 2024 07:10:06 +0300 Subject: [PATCH 08/15] === build number: 338 -> 339 === --- 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 60db7696..b1f8e467 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 338 +#define PROJECT_VERSION_BUILD_NO 339 #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 43602031b84ae303a7e3b4ff293be1a1e6c6a004 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 12 Sep 2024 16:05:08 +0200 Subject: [PATCH 09/15] gui: show_notification slot added + minor improvements (logs) --- src/gui/qt-daemon/application/mainwindow.cpp | 17 ++++++++++++++--- src/gui/qt-daemon/application/mainwindow.h | 1 + 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 90f3b422..2f34fba1 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Boolberry developers // Distributed under the MIT/X11 software license, see the accompanying @@ -714,9 +714,12 @@ bool MainWindow::show_inital() { TRY_ENTRY(); if (load_app_config()) + { restore_pos(true); + } else { + LOG_PRINT_L1("set defaults values to config"); m_config = AUTO_VAL_INIT(m_config); this->show(); QSize sz = AUTO_VAL_INIT(sz); @@ -976,6 +979,11 @@ QString MainWindow::start_backend(const QString& params) CATCH_ENTRY_FAIL_API_RESPONCE(); } +void MainWindow::show_notification(const QString& title, const QString& message) +{ + show_notification(title.toStdString(), message.toStdString()); +} + QString MainWindow::sync_call(const QString& func_name, const QString& params) { if (func_name == "test_call") @@ -1107,6 +1115,7 @@ bool MainWindow::get_is_disabled_notifications(const QString& param) } bool MainWindow::set_is_disabled_notifications(const bool& param) { + LOG_PRINT_L1("set_is_disabled_notifications: notifications were " << (m_config.disable_notifications ? "DISABLED" : "ENABLED") << " -> now " << (param ? "DISABLED" : "ENABLED")); m_config.disable_notifications = param; return m_config.disable_notifications; } @@ -2468,6 +2477,10 @@ QString MainWindow::print_log(const QString& param) void MainWindow::show_notification(const std::string& title, const std::string& message) { TRY_ENTRY(); + + if (m_config.disable_notifications) + return; + LOG_PRINT_L1("system notification: \"" << title << "\", \"" << message << "\""); // it's expected that title and message are utf-8 encoded! @@ -2482,5 +2495,3 @@ void MainWindow::show_notification(const std::string& title, const std::string& #endif CATCH_ENTRY2(void()); } - - diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index 0f575b6b..c0b37cf2 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -190,6 +190,7 @@ public: void on_menu_show(const QString& param); QString is_remnotenode_mode_preconfigured(const QString& param); QString start_backend(const QString& params); + void show_notification(const QString& title, const QString& message); QString async_call(const QString& func_name, const QString& params); QString sync_call(const QString& func_name, const QString& params); From 77d6939411fceb1919429c3819af4d3b101f8e85 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Thu, 12 Sep 2024 17:05:49 +0300 Subject: [PATCH 10/15] === build number: 339 -> 340 === --- 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 b1f8e467..a22706c8 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 339 +#define PROJECT_VERSION_BUILD_NO 340 #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 9d100503254af63e38d25954cec5e1577aa2cb23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= Date: Fri, 13 Sep 2024 01:29:09 +0500 Subject: [PATCH 11/15] coretests: asset_operation_in_consolidated_tx test added (#459) * coretests: Implement "asset_operation_in_consolidated_tx" test * Define "construct_tx" overload with a generation context argument --------- Co-authored-by: crypto.sowle --- tests/core_tests/chaingen.cpp | 42 +++++++++ tests/core_tests/chaingen.h | 16 ++++ tests/core_tests/chaingen_main.cpp | 3 +- tests/core_tests/hard_fork_4.cpp | 46 +--------- tests/core_tests/multiassets_test.cpp | 119 ++++++++++++++++++++++++++ tests/core_tests/multiassets_test.h | 13 +++ 6 files changed, 193 insertions(+), 46 deletions(-) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 750b0474..126df4f2 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1814,6 +1814,48 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s return construct_tx(keys_from, sources, destinations, empty_attachment, tx, tx_version, 0); } +bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + uint64_t tx_version, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint64_t expiration_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags, + uint64_t explicit_consolidated_tx_fee, + tx_generation_context& gen_context) +{ + // extra copy operation, but creating transaction is not sensitive to this + finalize_tx_param ftp {}; + ftp.tx_version = tx_version; + ftp.sources = sources; + ftp.prepared_destinations = destinations; + ftp.extra = extra; + ftp.attachments = attachments; + ftp.unlock_time = unlock_time; + // ftp.crypt_address = crypt_destination_addr; + ftp.expiration_time = expiration_time; + ftp.tx_outs_attr = tx_outs_attr; + ftp.shuffle = shuffle; + ftp.flags = flags; + ftp.mode_separate_fee = explicit_consolidated_tx_fee; + + finalized_tx ft = AUTO_VAL_INIT(ft); + ft.tx = tx; + ft.one_time_key = one_time_secret_key; + ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle + bool r = construct_tx(sender_account_keys, ftp, ft); + tx = ft.tx; + one_time_secret_key = ft.one_time_key; + gen_context = ft.ftp.gen_context; + return r; +} + uint64_t get_balance(const currency::account_keys& addr, const std::vector& blockchain, const map_hash2tx_t& mtx, bool dbg_log) { uint64_t res = 0; diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index d8d49100..11d274c8 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -673,6 +673,22 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s const currency::account_keys& keys_from, const currency::account_public_address& addr_to, uint64_t total_amount, size_t outputs_count, uint64_t fee, currency::transaction& tx, bool use_ref_by_id = false); +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint64_t expiration_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags, + uint64_t explicit_consolidated_tx_fee, + currency::tx_generation_context& gen_context); + void get_confirmed_txs(const std::vector& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs); bool find_block_chain(const std::vector& events, std::vector& blockchain, map_hash2tx_t& mtx, const crypto::hash& head); bool fill_tx_sources(std::vector& sources, const std::vector& events, diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index eaff24a3..c8c0e1a3 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1291,13 +1291,14 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(asset_depoyment_and_few_zc_utxos); GENERATE_AND_PLAY_HF(assets_and_pos_mining, "4-*"); GENERATE_AND_PLAY_HF(asset_emission_and_unconfirmed_balance, "4-*"); + GENERATE_AND_PLAY_HF(asset_operation_in_consolidated_tx, "4-*"); + GENERATE_AND_PLAY_HF(asset_operation_and_hardfork_checks, "4-*"); GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*"); GENERATE_AND_PLAY_HF(attachment_isolation_test, "4-*"); - GENERATE_AND_PLAY_HF(asset_operation_and_hardfork_checks, "4-*"); // GENERATE_AND_PLAY(gen_block_reward); // END OF TESTS */ diff --git a/tests/core_tests/hard_fork_4.cpp b/tests/core_tests/hard_fork_4.cpp index 396ac2ec..a87a1479 100644 --- a/tests/core_tests/hard_fork_4.cpp +++ b/tests/core_tests/hard_fork_4.cpp @@ -7,51 +7,7 @@ using namespace currency; -namespace currency -{ - bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, - const std::vector& destinations, - const std::vector& extra, - const std::vector& attachments, - transaction& tx, - uint64_t tx_version, - crypto::secret_key& one_time_secret_key, - uint64_t unlock_time, - uint64_t expiration_time, - uint8_t tx_outs_attr, - bool shuffle, - uint64_t flags, - uint64_t explicit_consolidated_tx_fee, - tx_generation_context& gen_context) - { - //extra copy operation, but creating transaction is not sensitive to this - finalize_tx_param ftp{}; - ftp.tx_version = tx_version; - ftp.sources = sources; - ftp.prepared_destinations = destinations; - ftp.extra = extra; - ftp.attachments = attachments; - ftp.unlock_time = unlock_time; - // ftp.crypt_address = crypt_destination_addr; - ftp.expiration_time = expiration_time; - ftp.tx_outs_attr = tx_outs_attr; - ftp.shuffle = shuffle; - ftp.flags = flags; - ftp.mode_separate_fee = explicit_consolidated_tx_fee; - - finalized_tx ft = AUTO_VAL_INIT(ft); - ft.tx = tx; - ft.one_time_key = one_time_secret_key; - ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle - bool r = construct_tx(sender_account_keys, ftp, ft); - tx = ft.tx; - one_time_secret_key = ft.one_time_key; - gen_context = ft.ftp.gen_context; - return r; - } -} // namespace currency - -void add_flags_to_all_destination_entries(const uint64_t flags, std::vector& destinations) +static void add_flags_to_all_destination_entries(const uint64_t flags, std::vector& destinations) { for(auto& de : destinations) de.flags |= flags; diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 12cabc51..cf3dbc19 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -1207,3 +1207,122 @@ bool asset_operation_and_hardfork_checks::c2( return true; } + +asset_operation_in_consolidated_tx::asset_operation_in_consolidated_tx() +{ + m_adb_alice_currency.total_max_supply = 1'000'000'000'000'000'000; + m_adb_alice_currency.current_supply = 1'000'000'000'000'000'000; + m_adb_alice_currency.ticker = "ALC"; + m_adb_alice_currency.full_name = "ALICE"; + m_adb_alice_currency.meta_info = "Currency created by Alice"; + m_adb_alice_currency.hidden_supply = false; + + m_ado_alice_currency.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; + m_ado_alice_currency.opt_asset_id = currency::null_pkey; + + REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_balances); + REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_alice_currency_not_registered); +} + +bool asset_operation_in_consolidated_tx::generate(std::vector& events) const +{ + // Test idea: make sure that the core rule prohibiting operations with assets in TX_FLAG_SIGNATURE_MODE_SEPARATE transactions works. + bool success {}; + transaction tx_2 {}; + uint64_t tx_version {}; + crypto::secret_key one_time {}; + tx_generation_context context_tx_2 {}; + GENERATE_ACCOUNT(miner); + GENERATE_ACCOUNT(alice); + GENERATE_ACCOUNT(bob); + + m_accounts.push_back(miner); + m_accounts.push_back(alice); + m_accounts.push_back(bob); + m_adb_alice_currency.owner = m_accounts.at(ALICE_ACC_IDX).get_public_address().spend_public_key; + m_ado_alice_currency.descriptor = m_adb_alice_currency; + + 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, bob, MK_TEST_COINS(10), blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0); + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_TX(events, tx_1, miner, alice, MK_TEST_COINS(10), blk_1r); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner, tx_1); + REWIND_BLOCKS_N(events, blk_2r, blk_2, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + // Miner sent 10 coins to Alice, 10 coins to Bob. + DO_CALLBACK(events, "assert_balances"); + + { + std::vector sources {}; + std::vector destinations {}; + + success = fill_tx_sources(sources, events, blk_2r, alice.get_keys(), MK_TEST_COINS(5), 1); + CHECK_AND_ASSERT_MES(success, false, "failed to fill transaction sources on step 1"); + destinations.emplace_back(MK_TEST_COINS(5), bob.get_public_address()); + destinations.emplace_back(MK_TEST_COINS(/* 10 - 5 - 1 = */ 4), alice.get_public_address()); + tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + success = construct_tx(alice.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TESTS_DEFAULT_FEE, + context_tx_2); + CHECK_AND_ASSERT_MES(success, false, "failed to construct transaction tx_2 on step 1"); + } + + // Transaction tx_2 hasn't been constructed completely yet. Core rejects tx_2. + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_2); + + { + std::vector sources {}; + std::vector destinations {}; + + success = fill_tx_sources(sources, events, blk_2r, bob.get_keys(), MK_TEST_COINS(5), 0); + CHECK_AND_ASSERT_MES(success, false, "failed to fill transaction sources on step 2"); + for(tx_source_entry& source : sources) + { + source.separately_signed_tx_complete = true; + } + destinations.emplace_back(MK_TEST_COINS(5), alice.get_public_address()); + destinations.emplace_back(MK_TEST_COINS(/* 10 - 5 - 0 = */ 5), bob.get_public_address()); + destinations.emplace_back(m_adb_alice_currency.current_supply, alice.get_public_address(), null_pkey); + tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + success = construct_tx(bob.get_keys(), sources, destinations, { m_ado_alice_currency }, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, + /* fee = */ 0, context_tx_2); + CHECK_AND_ASSERT_MES(success, false, "failed to construct transaction tx_2 on step 2"); + } + + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_2); + // Core rejects transaction tx_2. The balances of Alice, Bob haven't changed: Alice has 10 coins, Bob has 10 coins. + DO_CALLBACK(events, "assert_balances"); + // Alice's asset hasn't registered, because transaction tx_2 was rejected. + DO_CALLBACK(events, "assert_alice_currency_not_registered"); + + return true; +} + +bool asset_operation_in_consolidated_tx::assert_balances(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr alice_wallet{init_playtime_test_wallet(events, c, ALICE_ACC_IDX)}; + std::shared_ptr bob_wallet{init_playtime_test_wallet(events, c, BOB_ACC_IDX)}; + + alice_wallet->refresh(); + bob_wallet->refresh(); + + CHECK_AND_ASSERT_EQ(alice_wallet->balance(currency::native_coin_asset_id), MK_TEST_COINS(10)); + CHECK_AND_ASSERT_EQ(bob_wallet->balance(currency::native_coin_asset_id), MK_TEST_COINS(10)); + + return true; +} + +bool asset_operation_in_consolidated_tx::assert_alice_currency_not_registered(currency::core& c, size_t ev_index, const std::vector& events) +{ + crypto::point_t asset_id_point{}; + crypto::public_key asset_id{}; + currency::asset_descriptor_base stub{}; + + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ado_alice_currency, &asset_id_point, &asset_id), false, "fail to calculate asset id"); + CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().get_asset_info(asset_id, stub), false, "unregistered asset has info"); + + return true; +} diff --git a/tests/core_tests/multiassets_test.h b/tests/core_tests/multiassets_test.h index ce844292..70caf6fe 100644 --- a/tests/core_tests/multiassets_test.h +++ b/tests/core_tests/multiassets_test.h @@ -68,3 +68,16 @@ struct asset_operation_and_hardfork_checks : public wallet_test mutable currency::asset_descriptor_base m_adb_bye{}; mutable currency::asset_descriptor_operation m_ado_bye{}; }; + +struct asset_operation_in_consolidated_tx : public wallet_test +{ +public: + asset_operation_in_consolidated_tx(); + bool generate(std::vector& events) const; + bool assert_balances(currency::core& c, size_t ev_index, const std::vector& events); + bool assert_alice_currency_not_registered(currency::core& c, size_t ev_index, const std::vector& events); + +private: + mutable currency::asset_descriptor_base m_adb_alice_currency{}; + mutable currency::asset_descriptor_operation m_ado_alice_currency{}; +}; From 17aebd29b5ad865c65eb1663669c28430bc0287c Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Sat, 14 Sep 2024 21:46:09 +0400 Subject: [PATCH 12/15] implemented custom seed option(experimental) --- src/currency_core/account.cpp | 17 ++++++--- src/currency_core/account.h | 3 ++ src/simplewallet/simplewallet.cpp | 63 +++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 6a07b7c9..f5663826 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -60,7 +60,7 @@ namespace currency return m_keys; } //----------------------------------------------------------------- - void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password) + void account_base::crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password) { crypto::chacha8_key key = AUTO_VAL_INIT(key); crypto::generate_chacha8_key(password, key); @@ -71,16 +71,23 @@ namespace currency crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data); } //----------------------------------------------------------------- - std::string account_base::get_seed_phrase(const std::string& password) const + std::string account_base::get_seed_phrase(const std::string& password) const { if (m_keys_seed_binary.empty()) return ""; + return get_seed_phrase(password, m_keys_seed_binary); + } + //----------------------------------------------------------------- + std::string account_base::get_seed_phrase(const std::string& password, const std::vector& keys_seed_binary) const + { + if (keys_seed_binary.empty()) + return ""; - std::vector processed_seed_binary = m_keys_seed_binary; + std::vector processed_seed_binary = keys_seed_binary; if (!password.empty()) { //encrypt seed phrase binary data - crypt_with_pass(&m_keys_seed_binary[0], m_keys_seed_binary.size(), &processed_seed_binary[0], password); + crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &processed_seed_binary[0], password); } std::string keys_seed_text = tools::mnemonic_encoding::binary2text(processed_seed_binary); @@ -92,7 +99,7 @@ namespace currency CHECK_AND_ASSERT_THROW_MES(self_check_is_password_used == !password.empty(), "Account seed phrase internal error: password flag encoded wrong"); constexpr uint16_t checksum_max = tools::mnemonic_encoding::NUMWORDS >> 1; // maximum value of checksum - std::string binary_for_check_sum((const char*)&m_keys_seed_binary[0], m_keys_seed_binary.size()); + std::string binary_for_check_sum((const char*)&keys_seed_binary[0], keys_seed_binary.size()); binary_for_check_sum.append(password); crypto::hash h = crypto::cn_fast_hash(binary_for_check_sum.data(), binary_for_check_sum.size()); *reinterpret_cast(&h) = creation_timestamp_rounded; diff --git a/src/currency_core/account.h b/src/currency_core/account.h index 37a0c953..d732181d 100644 --- a/src/currency_core/account.h +++ b/src/currency_core/account.h @@ -56,6 +56,7 @@ namespace currency std::string get_public_address_str() const; std::string get_seed_phrase(const std::string& seed_password) const; + std::string get_seed_phrase(const std::string& password, const std::vector& keys_seed_binary) const; std::string get_tracking_seed() const; bool restore_from_seed_phrase(const std::string& seed_phrase, const std::string& seed_password); bool restore_from_tracking_seed(const std::string& tracking_seed); @@ -82,6 +83,8 @@ namespace currency static std::vector string_to_vector_of_chars(const std::string& v) { return std::vector(v.begin(), v.end()); } static bool is_seed_password_protected(const std::string& seed_phrase, bool& is_password_protected); static bool is_seed_tracking(const std::string& seed_phrase); + static void crypt_with_pass(const void* scr_data, std::size_t src_length, void* dst_data, const std::string& password); + BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_keys) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9d842fdf..f1f2ee7e 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -125,6 +125,7 @@ namespace { const command_line::arg_descriptor arg_wallet_file ("wallet-file", "Use wallet ", ""); const command_line::arg_descriptor arg_generate_new_wallet ("generate-new-wallet", "Generate new wallet and save it to or
.wallet by default", ""); + const command_line::arg_descriptor arg_derive_custom_seed("derive_custom_seed", "Derive seed phrase from custom 24-words secret(advanced option, do it on your own risk)", ""); const command_line::arg_descriptor arg_generate_new_auditable_wallet ("generate-new-auditable-wallet", "Generate new auditable wallet and store it to ", ""); const command_line::arg_descriptor arg_daemon_address ("daemon-address", "Use daemon instance at :", ""); const command_line::arg_descriptor arg_daemon_host ("daemon-host", "Use daemon instance at host instead of localhost", ""); @@ -2872,7 +2873,63 @@ bool search_for_wallet_file(const std::wstring &search_here/*, const std::string return false; } +int custom_seed_builder() +{ + success_msg_writer() << + "**********************************************************************\n" << + "This is an experimental tool that helps you create a custom seed phrase \n" + "based on your own 24 words. It can be extremely unsafe, so only use it \n" + "if you're confident in what you're doing.\n" + "**********************************************************************"; + success_msg_writer() << "Please enter 24 words that you want to use as base for the seed:"; + std::string seed_24; + std::getline(std::cin, seed_24); + + + std::list words; + std::string trimed_seed_24 = epee::string_tools::trim(seed_24); + boost::split(words, trimed_seed_24, boost::is_space(), boost::token_compress_on); + seed_24 = boost::algorithm::join(words, " "); + + std::string passphrase; + success_msg_writer() << "Please enter seed passphrase(it's highly recommended to use passphrase for custom seed):"; + std::getline(std::cin, passphrase); + if (passphrase.empty()) + { + success_msg_writer() << "Using unsecured seed(no passphrase)"; + } + else + { + std::string passphrase_confirmation; + success_msg_writer() << "Please confirm passphrase:"; + std::getline(std::cin, passphrase_confirmation); + if (passphrase_confirmation != passphrase) + { + success_msg_writer() << "Passphrase mismatched, try again"; + return EXIT_FAILURE; + } + } + + account_base acc; + acc.generate(); + std::string pass_protected_or_not = ""; + std::vector binary_from_seed = tools::mnemonic_encoding::text2binary(seed_24); + std::vector processed_binary_from_seed = binary_from_seed; + if (!passphrase.empty()) + { + //encrypt seed phrase binary data + account_base::crypt_with_pass(&binary_from_seed[0], binary_from_seed.size(), &processed_binary_from_seed[0], passphrase); + pass_protected_or_not = "(secured with passphrase)"; + } + { + pass_protected_or_not = "(!without passphrase!)"; + } + const std::string new_seed = acc.get_seed_phrase(passphrase, processed_binary_from_seed); + + success_msg_writer() << "Here is your seed" << pass_protected_or_not << "\n " << new_seed; + return EXIT_SUCCESS; +} int seed_doctor() { @@ -3142,6 +3199,8 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_no_password_confirmations); command_line::add_arg(desc_params, command_line::arg_generate_rpc_autodoc); command_line::add_arg(desc_params, arg_seed_doctor); + command_line::add_arg(desc_params, arg_derive_custom_seed); + tools::wallet_rpc_server::init_options(desc_params); @@ -3225,6 +3284,10 @@ int main(int argc, char* argv[]) return seed_doctor(); } + if (command_line::has_arg(vm, arg_derive_custom_seed)) + { + return custom_seed_builder(); + } if (command_line::has_arg(vm, tools::wallet_rpc_server::arg_rpc_bind_port)) { From a8adcc07b7ba231ecdd61d08501e0576d919c5d4 Mon Sep 17 00:00:00 2001 From: zano build machine Date: Sat, 14 Sep 2024 20:52:55 +0300 Subject: [PATCH 13/15] === build number: 340 -> 341 === --- 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 a22706c8..806a15d7 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 340 +#define PROJECT_VERSION_BUILD_NO 341 #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 35427f838124e8a0870e81048c4f154e68bc6ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=D1=91pa=20Dolgorukov?= Date: Tue, 17 Sep 2024 01:13:49 +0500 Subject: [PATCH 14/15] coretests: alt_chain_and_block_tx_fee_median test (#456) * coretests: alt_chain_and_block_tx_fee_median test * Run test "alt_chain_and_block_tx_fee_median" on run core tests * Edit the test preamble --- tests/core_tests/chain_switch_1.cpp | 238 ++++++++++++++++++++++++++++ tests/core_tests/chain_switch_1.h | 18 +++ tests/core_tests/chaingen_main.cpp | 2 +- 3 files changed, 257 insertions(+), 1 deletion(-) diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp index 2c830dd6..69ad2a28 100644 --- a/tests/core_tests/chain_switch_1.cpp +++ b/tests/core_tests/chain_switch_1.cpp @@ -817,3 +817,241 @@ bool chain_switching_when_out_spent_in_alt_chain_ref_id::generate(std::vector& events) const +{ + /* Test idea: check chain switching rules. + Rules before and after HF4 for PoW blocks are different. There're only PoW + blocks in the test situation. If the last blocks contain transactions (non + empty blocks), then the chain with the largest this_block_tx_fee_median on its + head becomes the main. + 0 10 11 21 22 + (0 ) - ... - (0r) - (1 ) - ... - (1r) - (2 ) + | main | \ + | | [tx_0] + | | + | | main + \ - (1a) \ - (2a) + \ + [tx_1] + Chain with head blk_1 versus chain with head blk_1a: chain with head blk_1 + is the main, because blocks 1, 1a are empty. + Chain with head blk_2 versus chain with head blk_2a: chain with head blk_2a + is the main, because blocks 2, 2a aren't empty and the fee of tx_1 is larger + than the fee of tx_0. + */ + + bool success{}; + bool hf4_active{}; + std::vector sources{}; + std::vector destinations{}; + transaction tx_0{}, tx_1{}; + uint64_t tx_version{}; + crypto::hash top_block{}; + + 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_NEXT_BLOCK(events, blk_1, blk_0r, miner); + MAKE_NEXT_BLOCK(events, blk_1a, blk_0r, miner); + + /* It is decided which chain will be the main: with the head blk_1 or with the + head blk_1a. + 0 10 11 + / - (1 ) + | + (0 ) - ... - (0r) + | + \ - (1a) + */ + + CHECK_AND_ASSERT_EQ(is_pos_block(blk_1), false); + CHECK_AND_ASSERT_EQ(is_pos_block(blk_1a), false); + CHECK_AND_ASSERT_EQ(get_block_height(blk_1), 11); + CHECK_AND_ASSERT_EQ(get_block_height(blk_1), get_block_height(blk_1a)); + + /* Blocks blk_1, blk_1a do not contain transactions (they are empty blocks). + Switching to the alternative chain with head blk_1a will not occur. The main + chain is the chain with the head blk_1. */ + + DO_CALLBACK_PARAMS(events, + "check_top_block", + params_top_block(get_block_height(blk_1), + get_block_hash(blk_1))); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // Transaction tx_0 is constructed and placed in block blk_2. + + success = fill_tx_sources_and_destinations( + events, + /* head = */ blk_1r, + /* from = */ miner.get_keys(), + /* to = */ miner.get_public_address(), + /* amount = */ MK_TEST_COINS(10), + /* fee = */ m_fee_tx_0_blk_2, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + tx_version = get_tx_version(get_block_height(blk_1r), + m_hardforks); + + success = construct_tx(miner.get_keys(), + sources, + destinations, + empty_attachment, + tx_0, + tx_version, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0"); + + ADD_CUSTOM_EVENT(events, tx_0); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner, tx_0); + + sources.clear(); + destinations.clear(); + + // Transaction tx_1 is constructed and placed in block blk_2a. + + tx_version = get_tx_version(get_block_height(blk_1r), + m_hardforks); + + success = fill_tx_sources_and_destinations( + events, + /* head = */ blk_1r, + /* from = */ miner.get_keys(), + /* to = */ miner.get_public_address(), + /* amount = */ MK_TEST_COINS(10), + /* fee = */ m_fee_tx_1_blk_2a, + /* nmix = */ 0, + sources, + destinations); + + CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); + + success = construct_tx(miner.get_keys(), + sources, + destinations, + empty_attachment, + tx_1, + tx_version, + 0); + + CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_1"); + + ADD_CUSTOM_EVENT(events, tx_1); + MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner, tx_1); + + /* It is decided which chain will be the main: with the head blk_2 or with the + head blk_2a. + 0 21 22 + / - (2 ) + | \ + | [tx_0] + | + (0 ) - ... - (1r) + | + | + | + \ - (2a) + \ + [tx_1] + */ + + CHECK_AND_ASSERT_EQ(is_pos_block(blk_2), false); + CHECK_AND_ASSERT_EQ(is_pos_block(blk_2a), false); + CHECK_AND_ASSERT_GREATER(m_fee_tx_1_blk_2a, m_fee_tx_0_blk_2); + CHECK_AND_ASSERT_EQ(get_block_height(blk_2), 22); + CHECK_AND_ASSERT_EQ(get_block_height(blk_2), get_block_height(blk_2a)); + + hf4_active = + m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, + get_block_height(blk_2) + 1); + + if (hf4_active) + { + /* With HF4 active, the chain with head blk_2a wins because transaction tx_1 + has a greater fee than transaction tx_0. The main chain is the chain with + the head blk_2a. */ + + DO_CALLBACK(events, "check_after_hf4"); + top_block = get_block_hash(blk_2a); + } + + else + { + /* The chains have the same commulative difficulty. Therefore, with HF4 + inactive, switching to the chain with the blk_2a head will not occur. The + main chain is the chain with the head blk_2. */ + + DO_CALLBACK(events, "check_before_hf4"); + top_block = get_block_hash(blk_2); + } + + DO_CALLBACK_PARAMS(events, + "check_top_block", + params_top_block(/* height = */ 22, top_block)); + + return true; +} + +bool alt_chain_and_block_tx_fee_median::check_after_hf4( + currency::core& c, + size_t ev_index, + const std::vector& events) +{ + block_extended_info bei{}; + const uint64_t height_block{22}; + + CHECK_AND_ASSERT_EQ( + m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, + height_block), + true); + + c.get_blockchain_storage().get_block_extended_info_by_height(height_block, + bei); + CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_1_blk_2a); + + return true; +} + +bool alt_chain_and_block_tx_fee_median::check_before_hf4( + currency::core& c, + size_t ev_index, + const std::vector& events) +{ + block_extended_info bei{}; + const uint64_t height_block{22}; + + CHECK_AND_ASSERT_EQ( + m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, + height_block), + false); + + c.get_blockchain_storage().get_block_extended_info_by_height(height_block, + bei); + CHECK_AND_ASSERT_EQ(bei.this_block_tx_fee_median, m_fee_tx_0_blk_2); + + return true; +} diff --git a/tests/core_tests/chain_switch_1.h b/tests/core_tests/chain_switch_1.h index f19e99b9..3d3b011b 100644 --- a/tests/core_tests/chain_switch_1.h +++ b/tests/core_tests/chain_switch_1.h @@ -82,3 +82,21 @@ struct chain_switching_when_out_spent_in_alt_chain_ref_id : public test_chain_un { bool generate(std::vector& events) const; }; + +struct alt_chain_and_block_tx_fee_median : public test_chain_unit_enchanced +{ + alt_chain_and_block_tx_fee_median(); + + bool generate(std::vector& events) const; + bool check_after_hf4(currency::core& c, + size_t ev_index, + const std::vector& events); + + bool check_before_hf4(currency::core& c, + size_t ev_index, + const std::vector& events); + +private: + const uint64_t m_fee_tx_0_blk_2{TESTS_DEFAULT_FEE}; + const uint64_t m_fee_tx_1_blk_2a{2 * m_fee_tx_0_blk_2}; +}; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index c8c0e1a3..07b5550f 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1140,7 +1140,7 @@ int main(int argc, char* argv[]) 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-*"); - + GENERATE_AND_PLAY_HF(alt_chain_and_block_tx_fee_median, "3-*"); // miscellaneous tests GENERATE_AND_PLAY(test_blockchain_vs_spent_keyimges); From 9d213b19b16c104abbd5b08679bdadeae6feeb98 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 17 Sep 2024 17:59:37 +0200 Subject: [PATCH 15/15] construct_miner_tx() doesn't clear result tx anymore, allowing to pass additional data in extra --- src/currency_core/currency_format_utils.cpp | 2 +- tests/core_tests/pos_block_builder.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index e9ef0eee..a2b05e2b 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -474,7 +474,7 @@ namespace currency } CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed."); - tx = AUTO_VAL_INIT_T(transaction); + // tx is not cleared intentionally to allow passing additional args in the extra/attachments tx.version = tx_version; tx_generation_context tx_gen_context{}; diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 8d394d0e..62561121 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -169,6 +169,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, uint64_t block_reward_without_fee = 0; m_block_reward = 0; size_t estimated_block_size = m_txs_total_size; + m_block.miner_tx = transaction{}; bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed"); @@ -177,6 +178,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, size_t cumulative_size = 0; for (size_t try_count = 0; try_count != 10; ++try_count) { + m_block.miner_tx = transaction{}; r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");