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{}; +};