diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index f2598dd3..be5a1417 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3857,17 +3857,12 @@ i_core_event_handler* blockchain_storage::get_event_handler() const //------------------------------------------------------------------ uint64_t blockchain_storage::validate_alias_reward(const transaction& tx, const std::string& alias) const { - - //validate alias coast uint64_t fee_for_alias = get_alias_coast(alias); - - //validate the price had been paid - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx); - - CHECK_AND_ASSERT_MES(found_alias_reward >= fee_for_alias, false, "registration of alias '" - << alias << "' goes with a reward of " << print_money(found_alias_reward) << " which is less than expected: " << print_money(fee_for_alias) - <<"(fee median: " << get_tx_fee_median() << ")" - << ", tx: " << get_transaction_hash(tx)); + uint64_t burnt_amount = 0; + CHECK_AND_ASSERT_MES(check_native_coins_amount_burnt_in_outs(tx, fee_for_alias, &burnt_amount), false, + "registration of alias '" << alias << "' failed due to incorrect reward; expected reward: " << print_money_brief(fee_for_alias) + << "; burnt amount: " << (tx.version <= TRANSACTION_VERSION_PRE_HF4 ? print_money_brief(burnt_amount) : std::string("hidden")) + << "; tx: " << get_transaction_hash(tx)); return true; } @@ -4332,12 +4327,12 @@ bool blockchain_storage::validate_all_aliases_for_new_median_mode() uint64_t fee_for_alias = get_alias_coast_from_fee(tei.m_alias.m_alias, median_fee); //validate the price had been paid - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_ptr->tx); - if (found_alias_reward < fee_for_alias) + uint64_t burnt_amount = 0; + if (!check_native_coins_amount_burnt_in_outs(tx_ptr->tx, fee_for_alias, &burnt_amount)) { - LOG_PRINT_RED_L0("[" << i << "]Found collision on alias: " << tei.m_alias.m_alias - << ", expected fee: " << print_money(fee_for_alias) << "(median:" << print_money(median_fee) << ")" - <<" found reward: " << print_money(found_alias_reward) <<". tx_id: " << tx_id); + LOG_PRINT_RED_L0("[" << i << "]Detected collision on alias: " << tei.m_alias.m_alias + << ", expected fee: " << print_money_brief(fee_for_alias) << " (median: " << print_money_brief(median_fee) << ")" + << " found reward: " << (tx_ptr->tx.version <= TRANSACTION_VERSION_PRE_HF4 ? print_money_brief(burnt_amount) : std::string("hidden")) << "; tx_id: " << tx_id); } } } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 102fe10d..3324ca55 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -3490,6 +3490,42 @@ namespace currency return true; } //--------------------------------------------------------------- + bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt /* = nullptr */) + { + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + { + uint64_t sum_of_bare_outs_burnt = 0; + for (const auto& out : tx.vout) + { + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, out) + if (out.target.type() != typeid(txout_to_key)) + continue; + const txout_to_key& o = boost::get(out.target); + if (o.key == null_pkey) + sum_of_bare_outs_burnt += out.amount; + VARIANT_SWITCH_END(); + } + if (p_amount_burnt) + *p_amount_burnt = sum_of_bare_outs_burnt; + return sum_of_bare_outs_burnt == amount; + } + + // post HF-4 txs + // assuming: zero out pubkey, explicit asset_id, zero amount blinding mask + crypto::point_t sum_of_amount_commitments = crypto::c_point_0; + for (const auto& out : tx.vout) + { + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_zarcanum, out_zc) + if (out_zc.stealth_address == null_pkey && out_zc.blinded_asset_id == native_coin_asset_id_1div8) + sum_of_amount_commitments += crypto::point_t(out_zc.amount_commitment).modify_mul8(); + VARIANT_SWITCH_END(); + } + return sum_of_amount_commitments == amount * native_coin_asset_id_pt; + } + //--------------------------------------------------------------- + // DEPRECATED, don't use -- sowle uint64_t get_amount_for_zero_pubkeys(const transaction& tx) { uint64_t found_alias_reward = 0; diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index ed4d67ff..8ccf34d5 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -399,7 +399,8 @@ namespace currency bool is_service_tx(const transaction& tx); bool does_tx_have_only_mixin_inputs(const transaction& tx); bool is_showing_sender_addres(const transaction& tx); - uint64_t get_amount_for_zero_pubkeys(const transaction& tx); + bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt = nullptr); + [[deprecated("Use check_native_coins_amount_burnt_in_outs instead")]] uint64_t get_amount_for_zero_pubkeys(const transaction& tx); //std::string get_comment_from_tx(const transaction& tx); std::string print_stake_kernel_info(const stake_kernel& sk); std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1fab53bc..58db3195 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2109,13 +2109,13 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) // read extra std::vector outs; - uint64_t tx_money_got_in_outs = 0; + uint64_t sum_of_received_native_outs = 0; crypto::public_key tx_pub_key = null_pkey; r = parse_and_validate_tx_extra(tx, tx_pub_key); THROW_IF_TRUE_WALLET_EX(!r, error::tx_extra_parse_error, tx); //check if we have money crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs, derivation); + r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, sum_of_received_native_outs, derivation); THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); //collect incomes @@ -2124,7 +2124,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) bool new_multisig_spend_detected = false; //check if we have spendings - uint64_t tx_money_spent_in_ins = 0; + uint64_t sum_of_spent_native_coin = 0; std::list spend_transfers; // check all outputs for spending (compare key images) for (size_t i = 0; i != tx.vin.size(); i++) @@ -2152,7 +2152,33 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) if (tid != UINT64_MAX) { // own output is being spent by this input - tx_money_spent_in_ins += intk.amount; + sum_of_spent_native_coin += intk.amount; + td.spent_indices.push_back(i); + spend_transfers.push_back(tid); + } + } + else if (in.type() == typeid(currency::txin_zc_input)) + { + // bad design -- remove redundancy like using wallet2::process_input_t() + const currency::txin_zc_input& zc = boost::get(in); + uint64_t tid = UINT64_MAX; + if (is_auditable() && is_watch_only()) + { + // tracking wallet, assuming all outputs are spent directly because of mix_attr = 1 + tid = get_directly_spent_transfer_index_by_input_in_tracking_wallet(zc); + } + else + { + // wallet with spend secret key -- we can calculate own key images and then search among them + auto it = m_key_images.find(zc.k_image); + if (it != m_key_images.end()) + { + tid = it->second; + } + } + + if (tid != UINT64_MAX) + { td.spent_indices.push_back(i); spend_transfers.push_back(tid); } @@ -2184,7 +2210,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) } - if (((!tx_money_spent_in_ins && tx_money_got_in_outs) || (currency::is_derivation_used_to_encrypt(tx, derivation) && !tx_money_spent_in_ins)) && !is_tx_expired(tx, tx_expiration_ts_median)) + if (((!sum_of_spent_native_coin && sum_of_received_native_outs) || (currency::is_derivation_used_to_encrypt(tx, derivation) && !sum_of_spent_native_coin)) && !is_tx_expired(tx, tx_expiration_ts_median)) { m_unconfirmed_in_transfers[tx_hash] = tx; if (m_unconfirmed_txs.count(tx_hash)) @@ -2192,22 +2218,22 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) //prepare notification about pending transaction wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, tx_hash); - + unconfirmed_wti.asset_id = native_coin_asset_id; // <-- TODO @#@# unconfirmed_wti.is_income = true; - prepare_wti(unconfirmed_wti, 0, m_core_runtime_config.get_core_time(), tx, tx_money_got_in_outs, td); + prepare_wti(unconfirmed_wti, 0, m_core_runtime_config.get_core_time(), tx, sum_of_received_native_outs, td); rise_on_transfer2(unconfirmed_wti); } - else if (tx_money_spent_in_ins || new_multisig_spend_detected) + else if (sum_of_spent_native_coin || new_multisig_spend_detected) { m_unconfirmed_in_transfers[tx_hash] = tx; if (m_unconfirmed_txs.count(tx_hash)) continue; //outgoing tx that was sent somehow not from this application instance uint64_t amount = 0; - /*if (!new_multisig_spend_detected && tx_money_spent_in_ins < tx_money_got_in_outs+get_tx_fee(tx)) + /*if (!new_multisig_spend_detected && tx_money_spent_in_ins < sum_of_received_native_outs+get_tx_fee(tx)) { WLT_LOG_ERROR("Transaction that get more then send: tx_money_spent_in_ins=" << tx_money_spent_in_ins - << ", tx_money_got_in_outs=" << tx_money_got_in_outs << ", tx_id=" << tx_hash); + << ", sum_of_received_native_outs=" << sum_of_received_native_outs << ", tx_id=" << tx_hash); } else*/ if (new_multisig_spend_detected) { @@ -2215,12 +2241,12 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) } else { - amount = tx_money_spent_in_ins - (tx_money_got_in_outs + get_tx_fee(tx)); + amount = sum_of_spent_native_coin - (sum_of_received_native_outs + get_tx_fee(tx)); } //prepare notification about pending transaction wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, tx_hash); - + unconfirmed_wti.asset_id = native_coin_asset_id; // <-- TODO @#@# unconfirmed_wti.is_income = false; prepare_wti(unconfirmed_wti, 0, m_core_runtime_config.get_core_time(), tx, amount, td); //mark transfers as spend to get correct balance diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 80a665ae..4bbe3302 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -397,7 +397,6 @@ namespace tools KV_SERIALIZE(m_spent_height) KV_SERIALIZE(m_flags) KV_SERIALIZE(m_amount) - //KV_SERIALIZE_N(m_opt_blinding_mask, "blinding_mask") KV_SERIALIZE_N(m_zc_info_ptr, "zc_out_info") KV_SERIALIZE_EPHEMERAL_N(uint64_t, tools::wallet2::transfer_details_base_to_amount, "amount") KV_SERIALIZE_EPHEMERAL_N(std::string, tools::wallet2::transfer_details_base_to_tx_hash, "tx_id") diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 6b80f9cd..5ff7a81c 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1842,7 +1842,7 @@ bool check_balance_via_wallet(const tools::wallet2& w, const char* account_name, bool r = true; -#define _CHECK_BAL(v) if (!(expected_##v == INVALID_BALANCE_VAL || v == expected_##v)) { r = false; LOG_PRINT_RED_L0("invalid " #v " balance, expected: " << print_money(expected_##v)); } +#define _CHECK_BAL(v) if (!(expected_##v == INVALID_BALANCE_VAL || v == expected_##v)) { r = false; LOG_PRINT_RED_L0("invalid " #v " balance, expected: " << print_money_brief(expected_##v)); } _CHECK_BAL(unlocked) _CHECK_BAL(awaiting_in) _CHECK_BAL(awaiting_out) diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 83d5da23..8d43323c 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -288,14 +288,17 @@ inline bool put_alias_via_tx_to_list(const currency::hard_forks_descriptor& hf, currency::account_keys& ak = const_cast(reward_acc.get_keys()); currency::get_aliases_reward_account(ak.account_address, ak.view_secret_key); - uint64_t fee_median = generator.get_last_n_blocks_fee_median(get_block_hash(head_block)); - uint64_t reward = currency::get_alias_coast_from_fee(ae.m_alias, fee_median); + uint64_t alias_reward = 0; + if (get_block_height(head_block) < ALIAS_MEDIAN_RECALC_INTERWAL) + alias_reward = get_alias_coast_from_fee(ae.m_alias, ALIAS_VERY_INITAL_COAST); // don't ask why + else + LOCAL_ASSERT(false); // not implemented yet, see also all the mess around blockchain_storage::get_tx_fee_median(), get_tx_fee_median_effective_index() etc. MAKE_TX_MIX_LIST_EXTRA_MIX_ATTR(events, tx_set, miner_acc, reward_acc, - reward, + alias_reward, 0, head_block, CURRENCY_TO_KEY_OUT_RELAXED, @@ -303,12 +306,11 @@ inline bool put_alias_via_tx_to_list(const currency::hard_forks_descriptor& hf, std::vector()); - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_set.back()); - if (found_alias_reward != reward) + uint64_t burnt_amount = 0; + if (!check_native_coins_amount_burnt_in_outs(tx_set.back(), alias_reward, &burnt_amount)) { - LOCAL_ASSERT(false); - CHECK_AND_ASSERT_MES(false, false, "wrong transaction constructed, first input value not match alias amount or account"); - return false; + CHECK_AND_ASSERT_MES(false, false, "alias reward was not found, expected: " << print_money_brief(alias_reward) + << "; burnt: " << (tx_set.back().version <= TRANSACTION_VERSION_PRE_HF4 ? print_money_brief(burnt_amount) : "hidden") << "; tx: " << get_transaction_hash(tx_set.back())); } return true; diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 892cb713..fc6a96cd 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -20,7 +20,10 @@ hard_fork_2_base_test::hard_fork_2_base_test(size_t hardfork_01_height, size_t h , m_hardfork_02_height(hardfork_02_height) , m_hardfork_03_height(CURRENCY_MAX_BLOCK_NUMBER) { - + m_hardforks.clear(); + m_hardforks.set_hardfork_height(1, m_hardfork_01_height); + m_hardforks.set_hardfork_height(2, m_hardfork_02_height); + m_hardforks.set_hardfork_height(3, m_hardfork_03_height); REGISTER_CALLBACK_METHOD(hard_fork_2_base_test, configure_core); } @@ -29,19 +32,11 @@ bool hard_fork_2_base_test::configure_core(currency::core& c, size_t ev_index, c currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config(); pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE; pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH; - pc.hard_forks.set_hardfork_height(1, m_hardfork_01_height); - pc.hard_forks.set_hardfork_height(2, m_hardfork_02_height); - pc.hard_forks.set_hardfork_height(3, m_hardfork_03_height); + pc.hard_forks = m_hardforks; c.get_blockchain_storage().set_core_runtime_config(pc); return true; } -void hard_fork_2_base_test::set_hard_fork_heights_to_generator(test_generator& generator) const -{ - generator.set_hardfork_height(1, m_hardfork_01_height); - generator.set_hardfork_height(2, m_hardfork_02_height); -} - //------------------------------------------------------------------------------ hard_fork_2_tx_payer_in_wallet::hard_fork_2_tx_payer_in_wallet() diff --git a/tests/core_tests/hard_fork_2.h b/tests/core_tests/hard_fork_2.h index bcca582e..caeb0eaf 100644 --- a/tests/core_tests/hard_fork_2.h +++ b/tests/core_tests/hard_fork_2.h @@ -13,8 +13,6 @@ struct hard_fork_2_base_test : virtual public test_chain_unit_enchanced hard_fork_2_base_test(size_t hardfork_01_height, size_t hardfork_02_height); bool configure_core(currency::core& c, size_t ev_index, const std::vector& events); - void set_hard_fork_heights_to_generator(test_generator& generator) const; - size_t m_hardfork_01_height; size_t m_hardfork_02_height; size_t m_hardfork_03_height; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index a1744253..8abd0ecf 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1670,8 +1670,7 @@ bool gen_wallet_alias_and_unconfirmed_txs::c1(currency::core& c, size_t ev_index std::vector stub_events_vec; MAKE_TEST_WALLET_TX_EXTRA(stub_events_vec, tx, bob_wlt, alias_reward, null_account, std::vector({ ai })); - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx); - CHECK_AND_ASSERT_MES(found_alias_reward == alias_reward, false, "Generated tx has invalid alias reward"); + CHECK_AND_ASSERT_MES(check_native_coins_amount_burnt_in_outs(tx, alias_reward), false, "Generated tx has invalid alias reward"); bool has_relates_alias_in_unconfirmed = false; bob_wlt->scan_tx_pool(has_relates_alias_in_unconfirmed); @@ -1707,8 +1706,7 @@ bool gen_wallet_alias_and_unconfirmed_txs::c2(currency::core& c, size_t ev_index std::vector stub_events_vec; MAKE_TEST_WALLET_TX_EXTRA(stub_events_vec, tx, bob_wlt, alias_reward, null_account, std::vector({ ai })); - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx); - CHECK_AND_ASSERT_MES(found_alias_reward == alias_reward, false, "Generated tx has invalid alias reward"); + CHECK_AND_ASSERT_MES(check_native_coins_amount_burnt_in_outs(tx, alias_reward), false, "Generated tx has invalid alias reward"); bool has_relates_alias_in_unconfirmed = false; bob_wlt->scan_tx_pool(has_relates_alias_in_unconfirmed);