From 67cfc35faf7e074c9d56a8faf89546325e63018b Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 31 May 2023 13:45:36 +0200 Subject: [PATCH 01/12] change of recent tx hsitory against multiassets --- src/currency_core/currency_config.h | 4 +- src/wallet/wallet2.h | 30 +------------ src/wallet/wallet_public_structs_defs.h | 60 +++++++++++++++++++------ 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 2ece02f4..2f306473 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -236,9 +236,9 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" #ifndef TESTNET -#define WALLET_FILE_SERIALIZATION_VERSION 154 +#define WALLET_FILE_SERIALIZATION_VERSION 155 #else -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+70) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+71) #endif #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 8818c7bc..c2352ece 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1200,7 +1200,7 @@ private: BOOST_CLASS_VERSION(tools::wallet2, WALLET_FILE_SERIALIZATION_VERSION) -BOOST_CLASS_VERSION(tools::wallet_public::wallet_transfer_info, 11) +BOOST_CLASS_VERSION(tools::wallet_public::wallet_transfer_info, 12) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 3) BOOST_CLASS_VERSION(tools::wallet2::transfer_details_base, 2) @@ -1282,34 +1282,6 @@ namespace boost a & x.spn; } - template - inline void serialize(Archive& a, tools::wallet_public::wallet_transfer_info& x, const boost::serialization::version_type ver) - { - - a & x.amount; - a & x.timestamp; - a & x.tx_hash; - a & x.height; - a & x.tx_blob_size; - a & x.payment_id; - a & x.remote_addresses; - a & x.is_income; - a & x.td; - a & x.tx; - a & x.remote_aliases; - a & x.comment; - a & x.contract; - a & x.selected_indicies; - a & x.marketplace_entries; - a & x.unlock_time; - if (ver < 10) - return; - a & x.service_entries; - if (ver < 11) - return; - a & x.asset_id; - } - template inline void serialize(Archive& a, tools::wallet_public::escrow_contract_details_basic& x, const boost::serialization::version_type ver) { diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 5e9cd041..03f6b6b7 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -89,50 +89,60 @@ namespace wallet_public #define WALLET_TRANSFER_INFO_FLAGS_HTLC_DEPOSIT static_cast(1 << 0) + struct wallet_sub_transfer_info + { + std::vector remote_addresses; //optional + std::vector remote_aliases; //optional, describe only if there only one remote address + uint64_t amount; + bool is_income; + crypto::public_key asset_id; // not blinded, not premultiplied by 1/8 + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(remote_addresses) + KV_SERIALIZE(remote_aliases) + KV_SERIALIZE(amount) + KV_SERIALIZE(is_income) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + + }; + struct wallet_transfer_info { - uint64_t amount; uint64_t timestamp; crypto::hash tx_hash; uint64_t height; //if height == 0 then tx is unconfirmed uint64_t unlock_time; uint32_t tx_blob_size; std::string payment_id; - std::vector remote_addresses; //optional - std::vector remote_aliases; //optional, describe only if there only one remote address std::string comment; - bool is_income; bool is_service; bool is_mixing; bool is_mining; uint64_t tx_type; wallet_transfer_info_details td; std::vector service_entries; + std::vector subtransfers; + //not included in streaming serialization uint64_t fee; bool show_sender; std::vector contract; - uint16_t extra_flags; + uint16_t extra_flags; uint64_t transfer_internal_index; - crypto::public_key asset_id; // not blinded, not premultiplied by 1/8 - - + //not included in kv serialization map currency::transaction tx; std::vector selected_indicies; std::list marketplace_entries; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(amount) KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash) KV_SERIALIZE(height) KV_SERIALIZE(unlock_time) KV_SERIALIZE(tx_blob_size) KV_SERIALIZE_BLOB_AS_HEX_STRING(payment_id) - KV_SERIALIZE(remote_addresses) - KV_SERIALIZE(remote_aliases) KV_SERIALIZE(comment) - KV_SERIALIZE(is_income) KV_SERIALIZE(timestamp) KV_SERIALIZE(td) KV_SERIALIZE(fee) @@ -144,8 +154,32 @@ namespace wallet_public KV_SERIALIZE(contract) KV_SERIALIZE(service_entries) KV_SERIALIZE(transfer_internal_index) - KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + KV_SERIALIZE(subtransfers) END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(key_offsets) // referring_input + BOOST_SERIALIZE(k_image) + BOOST_SERIALIZE(etc_details) + BOOST_SERIALIZE(tx_hash) + BOOST_SERIALIZE(height) + BOOST_SERIALIZE(unlock_time) + BOOST_SERIALIZE(tx_blob_size) + BOOST_SERIALIZE(payment_id) + BOOST_SERIALIZE(comment) + BOOST_SERIALIZE(timestamp) + BOOST_SERIALIZE(td) + BOOST_SERIALIZE(fee) + BOOST_SERIALIZE(is_service) + BOOST_SERIALIZE(is_mixing) + BOOST_SERIALIZE(is_mining) + BOOST_SERIALIZE(tx_type) + BOOST_SERIALIZE(show_sender) + BOOST_SERIALIZE(contract) + BOOST_SERIALIZE(service_entries) + BOOST_SERIALIZE(transfer_internal_index) + BOOST_SERIALIZE(subtransfers) + END_BOOST_SERIALIZATION() }; struct asset_balance_entry_base From b827779c7ce138316fe396f8b16f4b01d5d4fa5e Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 6 Jun 2023 23:05:53 +0200 Subject: [PATCH 02/12] deep refactoring of recent_transfers structure against confidential assets - still pretty much all broken --- src/currency_core/currency_config.h | 4 +- src/currency_core/currency_format_utils.cpp | 18 +- src/currency_core/currency_format_utils.h | 6 +- src/wallet/wallet2.cpp | 257 ++++++++++++-------- src/wallet/wallet2.h | 76 ++++-- src/wallet/wallet_id_adapter.h | 6 +- src/wallet/wallet_public_structs_defs.h | 27 +- tests/core_tests/atomic_tests.cpp | 2 +- tests/core_tests/escrow_wallet_tests.cpp | 2 +- tests/core_tests/hard_fork_2.cpp | 10 +- tests/core_tests/wallet_tests.cpp | 8 +- tests/core_tests/wallet_tests.h | 2 +- tests/core_tests/wallet_tests_basic.h | 6 +- 13 files changed, 260 insertions(+), 164 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index de929b98..f1ec0dfc 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -236,9 +236,9 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" #ifndef TESTNET -#define WALLET_FILE_SERIALIZATION_VERSION 155 +#define WALLET_FILE_SERIALIZATION_VERSION 160 #else -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+71) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+72) #endif #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 4504aa14..1a048254 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -2889,12 +2889,12 @@ namespace currency return true; } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation) + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, crypto::key_derivation& derivation) { crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); if (null_pkey == tx_pub_key) return false; - return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, sum_of_native_outs, derivation); + return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, derivation); } //--------------------------------------------------------------- bool check_tx_derivation_hint(const transaction& tx, const crypto::key_derivation& derivation) @@ -2922,7 +2922,7 @@ namespace currency return false; } //--------------------------------------------------------------- - bool lookup_acc_outs_genesis(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + bool lookup_acc_outs_genesis(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation) { uint64_t offset = 0; bool r = get_account_genesis_offset_by_address(get_account_address_as_str(acc.account_address), offset); @@ -2943,22 +2943,21 @@ namespace currency return true; } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation) + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation) { std::list htlc_info_list; - return lookup_acc_outs(acc, tx, tx_pub_key, outs, sum_of_native_outs, derivation, htlc_info_list); + return lookup_acc_outs(acc, tx, tx_pub_key, outs, derivation, htlc_info_list); } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation, std::list& htlc_info_list) + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation, std::list& htlc_info_list) { - sum_of_native_outs = 0; bool r = generate_key_derivation(tx_pub_key, acc.view_secret_key, derivation); CHECK_AND_ASSERT_MES(r, false, "unable to generate derivation from tx_pub = " << tx_pub_key << " * view_sec, invalid tx_pub?"); if (is_coinbase(tx) && get_block_height(tx) == 0 && tx_pub_key == ggenesis_tx_pub_key) { //genesis coinbase - return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, sum_of_native_outs, derivation); + return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, derivation); } if (!check_tx_derivation_hint(tx, derivation)) @@ -2975,7 +2974,6 @@ namespace currency if (is_out_to_acc(acc.account_address, t, derivation, output_index)) { outs.emplace_back(output_index, o.amount); - sum_of_native_outs += o.amount; } VARIANT_CASE_CONST(txout_multisig, t) if (is_out_to_acc(acc.account_address, t, derivation, output_index)) @@ -3016,8 +3014,6 @@ namespace currency crypto::point_t asset_id_pt = crypto::point_t(zo.blinded_asset_id).modify_mul8() - asset_id_blinding_mask * crypto::c_point_X; crypto::public_key asset_id = asset_id_pt.to_public_key(); outs.emplace_back(output_index, amount, amount_blinding_mask, asset_id_blinding_mask, asset_id); - if (asset_id == currency::native_coin_asset_id) - sum_of_native_outs += amount; } } VARIANT_SWITCH_END(); diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 0d8ebaf5..cbe82cc4 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -331,9 +331,9 @@ namespace currency bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index); bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation, std::list& htlc_info_list); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation, std::list& htlc_info_list); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, crypto::key_derivation& derivation); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 05fe16f5..ccf87cd0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -431,11 +431,10 @@ const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out //---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector* pglobal_indexes) { - std::vector recipients, remote_aliases; - process_unconfirmed(tx, recipients, remote_aliases); - //check for transaction spends - process_transaction_context ptc = AUTO_VAL_INIT(ptc); + process_transaction_context ptc(tx); + + process_unconfirmed(tx, ptc.recipients, ptc.remote_aliases); // check all outputs for spending (compare key images) ptc.coin_base_tx = is_coinbase(tx, ptc.is_pos_coinbase); @@ -443,6 +442,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t ptc.is_derived_from_coinbase = !ptc.is_pos_coinbase; ptc.height = height; + + for(auto& in : tx.vin) { ptc.sub_i = 0; @@ -464,7 +465,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { it->second.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; it->second.m_spent_height = height; - WLT_LOG_L0("Spent multisig out: " << multisig_id << ", amount: " << print_money(currency::get_amount_from_variant(in)) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height); + WLT_LOG_L0("Spent multisig out: " << multisig_id << ", amount: " << print_money(currency::get_amount_from_variant(in)) << ", with tx: " << ptc.tx_hash() << ", at height " << height); ptc.mtd.spent_indices.push_back(ptc.i); } } @@ -494,7 +495,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t m_transfers[it->second].m_spent_height = height; transfer_details_extra_option_htlc_info& tdeohi = get_or_add_field_to_variant_vector(td.varian_options); tdeohi.origin = in_htlc.hltc_origin; - tdeohi.redeem_tx_id = get_transaction_hash(tx); + tdeohi.redeem_tx_id = ptc.tx_hash(); } } VARIANT_SWITCH_END(); @@ -509,7 +510,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t uint64_t max_out_unlock_time = 0; std::vector outs; - uint64_t sum_of_native_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4 + //uint64_t sum_of_native_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4 crypto::public_key tx_pub_key = null_pkey; bool r = parse_and_validate_tx_extra(tx, tx_pub_key); THROW_IF_TRUE_WALLET_EX(!r, error::tx_extra_parse_error, tx); @@ -517,7 +518,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t //check for transaction income crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); std::list htlc_info_list; - r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, sum_of_native_outs, derivation, htlc_info_list); + r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, derivation, htlc_info_list); THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (!outs.empty()) @@ -605,17 +606,17 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size()); const transfer_details& local_td = m_transfers[it->second]; std::stringstream ss; - ss << "tx " << get_transaction_hash(tx) << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" << + ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" << local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height << ". This output can't ever be spent and will be skipped."; WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); - if (out.is_native_coin()) - { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); - sum_of_native_outs -= out.amount; - } + //if (out.is_native_coin()) + //{ + //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); + //sum_of_native_outs -= out.amount; + //} continue; // skip the output } } @@ -624,16 +625,16 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t out_get_mixin_attr(out_v) != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) { std::stringstream ss; - ss << "output #" << o << " from tx " << get_transaction_hash(tx) << " with amount " << print_money_brief(outs[i_in_outs].amount) + ss << "output #" << o << " from tx " << ptc.tx_hash() << " with amount " << print_money_brief(outs[i_in_outs].amount) << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)out_get_mixin_attr(out_v) << ". Output is IGNORED."; WLT_LOG_RED(ss.str(), LOG_LEVEL_0); if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str()); - if (out.is_native_coin()) - { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); - sum_of_native_outs -= out.amount; - } + //if (out.is_native_coin()) + //{ + //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); + //sum_of_native_outs -= out.amount; + //} continue; // skip the output } @@ -693,7 +694,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t //active htlc auto amount_gindex_pair = std::make_pair(td.m_amount, td.m_global_output_index); m_active_htlcs[amount_gindex_pair] = transfer_index; - m_active_htlcs_txid[get_transaction_hash(tx)] = transfer_index; + m_active_htlcs_txid[ptc.tx_hash()] = transfer_index; //add payer to extra options currency::tx_payer payer = AUTO_VAL_INIT(payer); if (het.is_wallet_owns_redeem) @@ -712,11 +713,15 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } + else + { + ptc.total_balance_change[td.get_asset_id()] += td.amount(); + add_transfer_to_transfers_cache(td.m_amount, transfer_index, td.get_asset_id()); + } + if (td.m_key_image != currency::null_ki) m_key_images[td.m_key_image] = transfer_index; - add_transfer_to_transfers_cache(td.m_amount, transfer_index, td.get_asset_id()); - if (is_watch_only() && is_auditable()) { WLT_CHECK_AND_ASSERT_MES_NO_RET(td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, "td.m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED validation failed"); @@ -732,17 +737,17 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t { if (td.is_native_coin()) { - WLT_LOG_L0("Received native coins, transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << get_transaction_hash(tx) << ", at height " << height); + WLT_LOG_L0("Received native coins, transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << ptc.tx_hash() << ", at height " << height); } else { // TODO @#@# output asset's ticker/name - WLT_LOG_L0("Received asset " << print16(td.get_asset_id()) << ", transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << get_transaction_hash(tx) << ", at height " << height); + WLT_LOG_L0("Received asset " << print16(td.get_asset_id()) << ", transfer #" << transfer_index << ", amount: " << print_money_brief(td.amount()) << (out_type_zc ? " (hidden)" : "") << ", with tx: " << ptc.tx_hash() << ", at height " << height); } } else if (out_type_htlc) { - WLT_LOG_L0("Detected HTLC[" << (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? "REDEEM" : "REFUND") << "], transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << get_transaction_hash(tx) << ", at height " << height); + WLT_LOG_L0("Detected HTLC[" << (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? "REDEEM" : "REFUND") << "], transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << ptc.tx_hash() << ", at height " << height); } } else if (out_type_multisig) @@ -753,37 +758,60 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t tdb.m_ptx_wallet_info = pwallet_info; tdb.m_internal_output_index = o; tdb.m_amount = outs[i_in_outs].amount; - WLT_LOG_L0("Received multisig, multisig out id: " << multisig_id << ", amount: " << tdb.amount() << ", with tx: " << get_transaction_hash(tx)); + WLT_LOG_L0("Received multisig, multisig out id: " << multisig_id << ", amount: " << tdb.amount() << ", with tx: " << ptc.tx_hash()); } else { - WLT_LOG_YELLOW("Unexpected output type: " << out_v.type().name() << ", out index: " << o << " in tx " << get_transaction_hash(tx), LOG_LEVEL_0); + WLT_LOG_YELLOW("Unexpected output type: " << out_v.type().name() << ", out index: " << o << " in tx " << ptc.tx_hash(), LOG_LEVEL_0); } } } } - std::string payment_id; - if (sum_of_native_outs != 0 && get_payment_id_from_tx(tx.attachment, payment_id)) - { - // TODO @#@# this code takes care only of native coins - // we need to add assets support - uint64_t received = (ptc.sum_of_own_native_inputs < sum_of_native_outs) ? sum_of_native_outs - ptc.sum_of_own_native_inputs : 0; - if (0 < received && payment_id.size()) + //do final calculations + bool has_in_transfers = false; + bool has_out_transfers = false; + for (const auto& bce : ptc.total_balance_change) + { + if (bce.second > 0) { - payment_details payment; - payment.m_tx_hash = currency::get_transaction_hash(tx); - payment.m_amount = received; - payment.m_block_height = height; - payment.m_unlock_time = max_out_unlock_time; - m_payments.emplace(payment_id, payment); - WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount)); + has_in_transfers = true; + } + else if (bce.second < 0) + { + has_out_transfers = true; } } + + std::string payment_id; + if (has_in_transfers && get_payment_id_from_tx(tx.attachment, payment_id) && payment_id.size()) + { + payment_details payment; + payment.m_tx_hash = ptc.tx_hash(); + payment.m_amount = 0; + payment.m_block_height = height; + payment.m_unlock_time = max_out_unlock_time; + + for (const auto& bce : ptc.total_balance_change) + { + if (bce.second > 0) + { + if (bce.first == currency::native_coin_asset_id) + { + payment.m_amount = static_cast(bce.second); + }else + { + payment.subtransfers.push_back(payment_details_subtransfer{ bce.first, static_cast(bce.second)}); + } + } + } + m_payments.emplace(payment_id, payment); + WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size()); + } - if (ptc.sum_of_own_native_inputs) + if (ptc.spent_own_native_inputs) { //check if there are asset_registration that belong to this wallet asset_descriptor_operation ado = AUTO_VAL_INIT(ado); @@ -797,13 +825,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (!r) { //not critical error, continue to work - LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << get_transaction_hash(tx)); + LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash()); }else { if (self_check != ado.descriptor.owner) { //still not critical error - LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << get_transaction_hash(tx)); + LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash()); } else { @@ -831,6 +859,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } + if (has_in_transfers || has_out_transfers) + { + ptc.timestamp = get_block_datetime(b); + handle_money(b, ptc); + } + + /* if (ptc.sum_of_own_native_inputs) {//this actually is transfer transaction, notify about spend if (ptc.sum_of_own_native_inputs > sum_of_native_outs) @@ -841,7 +876,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t {//strange transfer, seems that in one transaction have transfers from different wallets. if (!is_coinbase(tx)) { - WLT_LOG_RED("Unusual transaction " << currency::get_transaction_hash(tx) << ", sum_of_native_inputs: " << ptc.sum_of_own_native_inputs << ", sum_of_native_outs: " << sum_of_native_outs, LOG_LEVEL_0); + WLT_LOG_RED("Unusual transaction " << ptc.tx_hash() << ", sum_of_native_inputs: " << ptc.sum_of_own_native_inputs << ", sum_of_native_outs: " << sum_of_native_outs, LOG_LEVEL_0); } handle_money_received2(b, tx, (sum_of_native_outs - (ptc.sum_of_own_native_inputs - get_tx_fee(tx))), ptc.mtd); } @@ -854,7 +889,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } else if (currency::is_derivation_used_to_encrypt(tx, derivation)) { - //transaction doesn't transfer actually money, bud bring some information + //transaction doesn't transfer actually money, but bring some information handle_money_received2(b, tx, 0, ptc.mtd); } else if (ptc.mtd.spent_indices.size()) @@ -862,7 +897,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t // multisig spend detected handle_money_spent2(b, tx, 0, ptc.mtd, recipients, remote_aliases); } - } + }*/ } //---------------------------------------------------------------------------------------------------- void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att) @@ -883,11 +918,10 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i } } - - if (wti.is_income) + if (wti.is_income_mode_encryption()) { account_public_address sender_address = AUTO_VAL_INIT(sender_address); - wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ } ); + wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ }); if (wti.show_sender) wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); } @@ -902,7 +936,7 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i else addr_str = currency::get_account_address_and_payment_id_as_str(p.acc_addr, wti.payment_id); // show integrated address if there's a payment id provided wti.remote_addresses.push_back(addr_str); - LOG_PRINT_YELLOW("prepare_wti_decrypted_attachments, income=false, wti.amount = " << print_money_brief(wti.amount) << ", rem. addr = " << addr_str, LOG_LEVEL_0); + LOG_PRINT_YELLOW("prepare_wti_decrypted_attachments, income=false, rem. addr = " << addr_str, LOG_LEVEL_0); return true; // continue iterating through the container }); } @@ -1226,11 +1260,10 @@ bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc //scan outputs to figure out amount of change in escrow crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); std::vector outs; - uint64_t tx_money_got_in_outs = 0; - bool r = lookup_acc_outs(m_account.get_keys(), prop.tx_template, outs, tx_money_got_in_outs, derivation); + bool r = lookup_acc_outs(m_account.get_keys(), prop.tx_template, outs, derivation); THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to lookup_acc_outs for tx: " << get_transaction_hash(prop.tx_template)); - add_transfers_to_expiration_list(found_transfers, ed.expiration_time, tx_money_got_in_outs, wti.tx_hash); + add_transfers_to_expiration_list(found_transfers, ed.expiration_time, wti.tx_hash); WLT_LOG_GREEN("Locked " << found_transfers.size() << " transfers due to proposal " << ms_id, LOG_LEVEL_0); } @@ -1255,7 +1288,8 @@ bool wallet2::handle_release_contract(wallet_public::wallet_transfer_info& wti, else if (release_instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN) { change_contract_state(it->second, wallet_public::escrow_contract_details_basic::contract_released_burned, ms_id, wti); - wti.amount = it->second.private_detailes.amount_to_pay + it->second.private_detailes.amount_a_pledge + it->second.private_detailes.amount_b_pledge; + WLT_CHECK_AND_ASSERT_MES(wti.subtransfers.size(), false, "Unexpected subtransfers size"); //TODO: subject for refactoring + wti.subtransfers.back().amount = it->second.private_detailes.amount_to_pay + it->second.private_detailes.amount_a_pledge + it->second.private_detailes.amount_b_pledge; if (!it->second.is_a) { wti.fee = currency::get_tx_fee(wti.tx); @@ -1312,7 +1346,8 @@ bool wallet2::handle_contract(wallet_public::wallet_transfer_info& wti, const bc //in code which know escrow protocol, and we know that fee paid by B(seller) if (ed.is_a) { - wti.amount += wti.fee; + WLT_CHECK_AND_ASSERT_MES(wti.subtransfers.size(), false, "Unexpected subtransfers size"); //TODO: subject for refactoring + wti.subtransfers.back().amount += wti.fee; wti.fee = 0; } @@ -1413,19 +1448,19 @@ bool wallet2::process_contract_info(wallet_public::wallet_transfer_info& wti, co return true; } //----------------------------------------------------------------------------------------------------- -void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, uint64_t height, uint64_t timestamp, const currency::transaction& tx, uint64_t amount, const money_transfer2_details& td) +void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context) { PROFILE_FUNC("wallet2::prepare_wti"); - wti.tx = tx; - wti.amount = amount; - wti.height = height; - fill_transfer_details(tx, td, wti.td); - wti.unlock_time = get_max_unlock_time_from_receive_indices(tx, td); - wti.timestamp = timestamp; + wti.tx = tx_process_context.tx; + + wti.height = tx_process_context.height; + fill_transfer_details(tx_process_context.tx, tx_process_context.mtd, wti.td); + wti.unlock_time = get_max_unlock_time_from_receive_indices(tx_process_context.tx, tx_process_context.mtd); + wti.timestamp = tx_process_context.timestamp; wti.tx_blob_size = static_cast(currency::get_object_blobsize(wti.tx)); - wti.tx_hash = currency::get_transaction_hash(tx); + wti.tx_hash = tx_process_context.tx_hash(); load_wallet_transfer_info_flags(wti); - bc_services::extract_market_instructions(wti.marketplace_entries, tx.attachment); + bc_services::extract_market_instructions(wti.marketplace_entries, wti.tx.attachment); // escrow transactions, which are built with TX_FLAG_SIGNATURE_MODE_SEPARATE flag actually encrypt attachments // with buyer as a sender, and seller as receiver, despite the fact that for both sides transaction seen as outgoing @@ -1433,19 +1468,20 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, uint64_t hei //we check if spent_indices have zero then input do not belong to this account, which means that we are seller for this //escrow, and decryption should be processed as income flag - bool decrypt_attachment_as_income = wti.is_income; + //let's assume that the one who pays for tx fee is sender of tx + bool decrypt_attachment_as_income = !(tx_process_context.total_balance_change.count(currency::native_coin_asset_id) && tx_process_context.total_balance_change.at(currency::native_coin_asset_id) < 0 ); std::vector decrypted_att; - if (wti.tx_type == GUI_TX_TYPE_ESCROW_TRANSFER && std::find(td.spent_indices.begin(), td.spent_indices.end(), 0) == td.spent_indices.end()) + if (wti.tx_type == GUI_TX_TYPE_ESCROW_TRANSFER && std::find(tx_process_context.mtd.spent_indices.begin(), tx_process_context.mtd.spent_indices.end(), 0) == tx_process_context.mtd.spent_indices.end()) decrypt_attachment_as_income = true; - decrypt_payload_items(decrypt_attachment_as_income, tx, m_account.get_keys(), decrypted_att); - if ((is_watch_only() && !wti.is_income)|| (height > 638000 && !have_type_in_variant_container(decrypted_att))) + decrypt_payload_items(decrypt_attachment_as_income, wti.tx, m_account.get_keys(), decrypted_att); + if ((is_watch_only() && !decrypt_attachment_as_income)|| (height > 638000 && !have_type_in_variant_container(decrypted_att))) { remove_field_of_type_from_extra(decrypted_att); remove_field_of_type_from_extra(decrypted_att); } - if (is_watch_only() && !wti.is_income) + if (is_watch_only() && !decrypt_attachment_as_income) { remove_field_of_type_from_extra(decrypted_att); } @@ -1453,19 +1489,6 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, uint64_t hei process_contract_info(wti, decrypted_att); } //---------------------------------------------------------------------------------------------------- -void wallet2::handle_money_received2(const currency::block& b, const currency::transaction& tx, uint64_t amount, const money_transfer2_details& td) -{ - //decrypt attachments - m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); - wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); - wti.is_income = true; - // TODO @#@# this function is only able to handle native coins atm, consider changing -- sowle - wti.asset_id = native_coin_asset_id; - prepare_wti(wti, get_block_height(b), get_block_datetime(b), tx, amount, td); - WLT_LOG_L1("[MONEY RECEIVED]: " << epee::serialization::store_t_to_json(wti)); - rise_on_transfer2(wti); -} -//---------------------------------------------------------------------------------------------------- void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti) { PROFILE_FUNC("wallet2::rise_on_transfer2"); @@ -1475,22 +1498,11 @@ void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti) uint64_t mined_balance = 0; this->balance(balances, mined_balance); m_wcallback->on_transfer2(wti, balances, mined_balance); - - // TODO @#@# bad design, CZ we need to redesign balance() functions regarding getting mined and unlocked balances for the native coin - uint64_t unlocked_balance = 0, native_balance = 0; - for (auto& el : balances) - { - if (el.asset_info.asset_id == currency::native_coin_asset_id) - { - native_balance = el.total; - unlocked_balance = el.unlocked; - break; - } - } // second call for legacy callback handlers - m_wcallback->on_transfer2(wti, native_balance, unlocked_balance, mined_balance); + m_wcallback->on_transfer2(wti, balances, mined_balance); } //---------------------------------------------------------------------------------------------------- +/* void wallet2::handle_money_spent2(const currency::block& b, const currency::transaction& in_tx, uint64_t amount, @@ -1509,6 +1521,54 @@ void wallet2::handle_money_spent2(const currency::block& b, rise_on_transfer2(wti); } //---------------------------------------------------------------------------------------------------- +void wallet2::handle_money_received2(const currency::block& b, const currency::transaction& tx, uint64_t amount, const money_transfer2_details& td) +{ + //decrypt attachments + m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); + wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); + wti.is_income = true; + // TODO @#@# this function is only able to handle native coins atm, consider changing -- sowle + wti.asset_id = native_coin_asset_id; + prepare_wti(wti, get_block_height(b), get_block_datetime(b), tx, amount, td); + WLT_LOG_L1("[MONEY RECEIVED]: " << epee::serialization::store_t_to_json(wti)); + rise_on_transfer2(wti); +} +*/ +//---------------------------------------------------------------------------------------------------- +void wallet2::handle_money(const currency::block& b, const process_transaction_context& tx_process_context) +{ + m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); + wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); + wti.remote_addresses = tx_process_context.recipients; + wti.remote_aliases = tx_process_context.remote_aliases; + for (const auto bce : tx_process_context.total_balance_change) + { + wallet_sub_transfer_info wsti = AUTO_VAL_INIT(wsti); + wsti.asset_id = bce.first; + if (bce.second == 0) + { + continue; + } + else if (bce.second > 0) + { + //in transfer + wsti.is_income = true; + wsti.amount = static_cast(bce.second); + } + else + { + //out transfer + wsti.is_income = false; + wsti.amount = static_cast(bce.second * (-1)); + } + wti.push_back(wsti); + } + + prepare_wti(wti, tx_process_context); + WLT_LOG_L1("[MONEY SPENT]: " << epee::serialization::store_t_to_json(wti)); + rise_on_transfer2(wti); +} +//---------------------------------------------------------------------------------------------------- void wallet2::process_unconfirmed(const currency::transaction& tx, std::vector& recipients, std::vector& remote_aliases) { auto unconf_it = m_unconfirmed_txs.find(get_transaction_hash(tx)); @@ -4799,7 +4859,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details& finalize_transaction(ftp, tx, one_time_key, false); } //---------------------------------------------------------------------------------------------------- -void wallet2::add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id) +void wallet2::add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, const crypto::hash& related_tx_id) { // check all elements in selected_transfers for being already mentioned in m_money_expirations std::vector selected_transfers_local; @@ -4821,7 +4881,6 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele m_money_expirations.push_back(AUTO_VAL_INIT(expiration_entry_info())); m_money_expirations.back().expiration_time = expiration; m_money_expirations.back().selected_transfers = selected_transfers_local; - m_money_expirations.back().change_amount = change_amount; m_money_expirations.back().related_tx_id = related_tx_id; std::stringstream ss; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0e800111..f8f13b3d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -120,7 +120,6 @@ namespace tools virtual ~i_wallet2_callback() = default; virtual void on_new_block(uint64_t /*height*/, const currency::block& /*block*/) {} - virtual void on_transfer2(const wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) {} // this one is left for compatibility, one day we need to get rid of it virtual void on_transfer2(const wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) {} virtual void on_pos_block_found(const currency::block& /*block*/) {} virtual void on_sync_progress(const uint64_t& /*percents*/) {} @@ -438,12 +437,32 @@ namespace tools }; + struct payment_details_subtransfer + { + crypto::public_key asset_id = currency::null_pkey; + uint64_t amount = 0; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(asset_id) + BOOST_SERIALIZE(amount) + END_BOOST_SERIALIZATION() + }; + struct payment_details { crypto::hash m_tx_hash = currency::null_hash; - uint64_t m_amount = 0; + uint64_t m_amount = 0; // native coins amount uint64_t m_block_height = 0; uint64_t m_unlock_time = 0; + std::vector subtransfers; //subtransfers added for confidential asset only, native amount should be stored in m_amount (for space saving) + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_tx_hash) + BOOST_SERIALIZE(m_amount) + BOOST_SERIALIZE(m_block_height) + BOOST_SERIALIZE(m_unlock_time) + BOOST_SERIALIZE(subtransfers) + END_BOOST_SERIALIZATION() }; struct mining_context : public currency::pos_mining_context @@ -466,7 +485,6 @@ namespace tools struct expiration_entry_info { std::vector selected_transfers; - uint64_t change_amount = 0; uint64_t expiration_time = 0; crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) }; @@ -533,7 +551,9 @@ namespace tools struct process_transaction_context { - uint64_t sum_of_own_native_inputs = 0; // old-fashioned bare inputs or ZC inputs referring to native coin asset_id + process_transaction_context(const currency::transaction& t) : tx(t) {} + const currency::transaction& tx; + bool spent_own_native_inputs = false; // check all outputs for spending (compare key images) money_transfer2_details mtd; bool is_pos_coinbase = false; @@ -543,6 +563,21 @@ namespace tools size_t i = 0; size_t sub_i = 0; uint64_t height = 0; + uint64_t timestamp = 0; + std::map total_balance_change; + std::vector recipients; + std::vector remote_aliases; + + const crypto::hash& tx_hash() const + { + if (tx_hash_ == currency::null_hash) + { + tx_hash_ = get_transaction_hash(tx); + } + return tx_hash_; + } + private: + mutable crypto::hash tx_hash_ = currency::null_hash; }; @@ -988,7 +1023,7 @@ private: // -------- t_transport_state_notifier ------------------------------------------------ virtual void notify_state_change(const std::string& state_code, const std::string& details = std::string()); // ------------------------------------------------------------------------------------ - void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id); + void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, const crypto::hash& related_tx_id); void remove_transfer_from_expiration_list(uint64_t transfer_index); void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature, keys_file_data& kf_data); void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector* pglobal_indexes); @@ -1015,18 +1050,11 @@ private: const std::vector& splitted_dsts); void update_current_tx_limit(); - void prepare_wti(wallet_public::wallet_transfer_info& wti, uint64_t height, uint64_t timestamp, const currency::transaction& tx, uint64_t amount, const money_transfer2_details& td); - void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att); - void handle_money_received2(const currency::block& b, - const currency::transaction& tx, - uint64_t amount, - const money_transfer2_details& td); - void handle_money_spent2(const currency::block& b, - const currency::transaction& in_tx, - uint64_t amount, - const money_transfer2_details& td, - const std::vector& recipients, - const std::vector& recipients_aliases); + void prepare_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); + void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att); + void handle_money(const currency::block& b, const process_transaction_context& tx_process_context); + + void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); std::string get_alias_for_address(const std::string& addr); @@ -1267,15 +1295,6 @@ namespace boost a & x.is_wallet_owns_redeem; a & x.transfer_index; } - - template - inline void serialize(Archive& a, tools::wallet2::payment_details& x, const boost::serialization::version_type ver) - { - a & x.m_tx_hash; - a & x.m_amount; - a & x.m_block_height; - a & x.m_unlock_time; - } template inline void serialize(Archive& a, tools::wallet_public::wallet_transfer_info_details& x, const boost::serialization::version_type ver) @@ -1350,8 +1369,11 @@ namespace tools if (tr_index != UINT64_MAX) { transfer_details& td = m_transfers[tr_index]; + ptc.total_balance_change[td.get_asset_id()] -= td.amount(); if (td.is_native_coin()) - ptc.sum_of_own_native_inputs += td.m_amount; + { + ptc.spent_own_native_inputs = true; + } uint32_t flags_before = td.m_flags; td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; td.m_spent_height = ptc.height; diff --git a/src/wallet/wallet_id_adapter.h b/src/wallet/wallet_id_adapter.h index e31e2fab..e794795f 100644 --- a/src/wallet/wallet_id_adapter.h +++ b/src/wallet/wallet_id_adapter.h @@ -12,7 +12,7 @@ class i_backend_wallet_callback { public: virtual void on_new_block(size_t wallet_id, uint64_t /*height*/, const currency::block& /*block*/) {} - virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) {} + virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) {} virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/) {} virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/) {} virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti) {} @@ -32,8 +32,8 @@ struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback virtual void on_new_block(uint64_t height, const currency::block& block) { m_pbackend->on_new_block(m_wallet_id, height, block); } - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) { - m_pbackend->on_transfer2(m_wallet_id, wti, balance, unlocked_balance, total_mined); + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { + m_pbackend->on_transfer2(m_wallet_id, wti, balances, total_mined); } virtual void on_pos_block_found(const currency::block& wti) { m_pbackend->on_pos_block_found(m_wallet_id, wti); diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 03f6b6b7..35e841f9 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -91,20 +91,22 @@ namespace wallet_public struct wallet_sub_transfer_info { - std::vector remote_addresses; //optional - std::vector remote_aliases; //optional, describe only if there only one remote address uint64_t amount; bool is_income; crypto::public_key asset_id; // not blinded, not premultiplied by 1/8 BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(remote_addresses) - KV_SERIALIZE(remote_aliases) KV_SERIALIZE(amount) KV_SERIALIZE(is_income) KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) END_KV_SERIALIZE_MAP() + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(amount) + BOOST_SERIALIZE(is_income) + BOOST_SERIALIZE(asset_id) + END_BOOST_SERIALIZATION() + }; struct wallet_transfer_info @@ -122,6 +124,9 @@ namespace wallet_public uint64_t tx_type; wallet_transfer_info_details td; std::vector service_entries; + std::vector remote_addresses; //optional + std::vector remote_aliases; //optional, describe only if there only one remote address + std::vector subtransfers; //not included in streaming serialization @@ -154,6 +159,8 @@ namespace wallet_public KV_SERIALIZE(contract) KV_SERIALIZE(service_entries) KV_SERIALIZE(transfer_internal_index) + KV_SERIALIZE(remote_addresses) + KV_SERIALIZE(remote_aliases) KV_SERIALIZE(subtransfers) END_KV_SERIALIZE_MAP() @@ -178,8 +185,20 @@ namespace wallet_public BOOST_SERIALIZE(contract) BOOST_SERIALIZE(service_entries) BOOST_SERIALIZE(transfer_internal_index) + BOOST_SERIALIZE(remote_addresses) + BOOST_SERIALIZE(remote_aliases) BOOST_SERIALIZE(subtransfers) END_BOOST_SERIALIZATION() + + bool is_income_mode_encryption() + { + for (const auto& st : subtransfers) + { + if (st.asset_id == currency::native_coin_asset_id) + return st.is_income; + } + return true; + } }; struct asset_balance_entry_base diff --git a/tests/core_tests/atomic_tests.cpp b/tests/core_tests/atomic_tests.cpp index a6176fc1..41382a51 100644 --- a/tests/core_tests/atomic_tests.cpp +++ b/tests/core_tests/atomic_tests.cpp @@ -24,7 +24,7 @@ using namespace currency; struct wallet_tests_callback_handler : public tools::i_wallet2_callback { - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { all_wtis.push_back(wti); } diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index 5b013f5d..6cee1610 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -17,7 +17,7 @@ using namespace currency; struct wallet_tests_callback_handler : public tools::i_wallet2_callback { - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { all_wtis.push_back(wti); } diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 72b21bea..8f434d2b 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -140,7 +140,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons size_t callback_counter = 0; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); @@ -234,7 +234,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(2), "incorrect wti.amount = " << print_money_brief(wti.amount)); CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); @@ -367,7 +367,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); @@ -409,7 +409,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(4), "incorrect wti.amount = " << print_money_brief(wti.amount)); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); @@ -1003,7 +1003,7 @@ bool hard_fork_2_awo_wallets_basic_test::c1(currency::core& c, size bool callback_called = false; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&callback_called](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&callback_called](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { callback_called = true; return true; } diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 8abd0ecf..dc2f58f0 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1586,7 +1586,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e return true; } -void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) +void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { m_on_transfer2_called = true; //try { @@ -1819,7 +1819,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ uint64_t biggest_alias_reward = get_alias_coast_from_fee("a", TESTS_DEFAULT_FEE); std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { return std::count(wti.remote_aliases.begin(), wti.remote_aliases.end(), "minerminer") == 1 && wti.amount == biggest_alias_reward; } @@ -3295,7 +3295,7 @@ bool wallet_unconfimed_tx_balance::c1(currency::core& c, size_t ev_index, const bool callback_is_ok = false; // this callback will ba called from within wallet2::transfer() below std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&callback_is_ok](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool + [&callback_is_ok](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_MES(balance == MK_TEST_COINS(70), false, "invalid balance: " << print_money_brief(balance)); CHECK_AND_ASSERT_MES(unlocked_balance == MK_TEST_COINS(50), false, "invalid unlocked_balance: " << print_money_brief(unlocked_balance)); @@ -3444,7 +3444,7 @@ bool wallet_sending_to_integrated_address::c1(currency::core& c, size_t ev_index bool callback_succeded = false; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { LOG_PRINT_YELLOW("on_transfer: " << print_money_brief(wti.amount) << " pid len: " << wti.payment_id.size() << " remote addr: " << (wti.remote_addresses.size() > 0 ? wti.remote_addresses[0] : ""), LOG_LEVEL_0); if (wti.payment_id.empty()) return true; // skip another outputs diff --git a/tests/core_tests/wallet_tests.h b/tests/core_tests/wallet_tests.h index eb54960b..251ff43b 100644 --- a/tests/core_tests/wallet_tests.h +++ b/tests/core_tests/wallet_tests.h @@ -111,7 +111,7 @@ struct gen_wallet_decrypted_attachments : public wallet_test, virtual public too bool generate(std::vector& events) const; // intrface tools::i_wallet2_callback - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override; + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override; private: mutable bool m_on_transfer2_called; diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 425c81f6..c40ebad4 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -60,7 +60,7 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback m_called = false; } - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override { m_called = true; m_result = false; @@ -92,9 +92,9 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback { - typedef std::function Func; + typedef std::function&, uint64_t)> Func; wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {} - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override { m_result = m_callback(wti, balance, unlocked_balance, total_mined); } From 5f79730c20c177e7e384e572431b027c3a9b3910 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 7 Jun 2023 23:29:41 +0200 Subject: [PATCH 03/12] deep refactoring of recent_transfers structure against confidential assets - fixes over scan_tx_pool --- src/wallet/wallet2.cpp | 93 ++++++++++++++++++++---------------------- src/wallet/wallet2.h | 2 +- 2 files changed, 45 insertions(+), 50 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ccf87cd0..d3bbdf4f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1476,7 +1476,7 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces decrypt_payload_items(decrypt_attachment_as_income, wti.tx, m_account.get_keys(), decrypted_att); - if ((is_watch_only() && !decrypt_attachment_as_income)|| (height > 638000 && !have_type_in_variant_container(decrypted_att))) + if ((is_watch_only() && !decrypt_attachment_as_income)|| (wti.height > 638000 && !have_type_in_variant_container(decrypted_att))) { remove_field_of_type_from_extra(decrypted_att); remove_field_of_type_from_extra(decrypted_att); @@ -1534,16 +1534,14 @@ void wallet2::handle_money_received2(const currency::block& b, const currency::t rise_on_transfer2(wti); } */ -//---------------------------------------------------------------------------------------------------- -void wallet2::handle_money(const currency::block& b, const process_transaction_context& tx_process_context) + //---------------------------------------------------------------------------------------------------- +void wallet2::make_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context) { - m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); - wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); wti.remote_addresses = tx_process_context.recipients; wti.remote_aliases = tx_process_context.remote_aliases; for (const auto bce : tx_process_context.total_balance_change) { - wallet_sub_transfer_info wsti = AUTO_VAL_INIT(wsti); + wallet_public::wallet_sub_transfer_info wsti = AUTO_VAL_INIT(wsti); wsti.asset_id = bce.first; if (bce.second == 0) { @@ -1561,10 +1559,17 @@ void wallet2::handle_money(const currency::block& b, const process_transaction_c wsti.is_income = false; wsti.amount = static_cast(bce.second * (-1)); } - wti.push_back(wsti); + wti.subtransfers.push_back(wsti); } prepare_wti(wti, tx_process_context); +} +//---------------------------------------------------------------------------------------------------- +void wallet2::handle_money(const currency::block& b, const process_transaction_context& tx_process_context) +{ + m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); + wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); + make_wti_from_process_transaction_context(wti, tx_process_context); WLT_LOG_L1("[MONEY SPENT]: " << epee::serialization::store_t_to_json(wti)); rise_on_transfer2(wti); } @@ -2165,13 +2170,14 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) for (const auto &tx_blob : res.txs) { currency::transaction tx; - money_transfer2_details td; + //money_transfer2_details td; + process_transaction_context ptc(tx); bool r = parse_and_validate_tx_from_blob(tx_blob, tx); THROW_IF_TRUE_WALLET_EX(!r, error::tx_parse_error, tx_blob); has_related_alias_in_unconfirmed |= has_related_alias_entry_unconfirmed(tx); - crypto::hash tx_hash = currency::get_transaction_hash(tx); - auto it = unconfirmed_in_transfers_local.find(tx_hash); + //crypto::hash tx_hash = currency::get_transaction_hash(tx); + auto it = unconfirmed_in_transfers_local.find(ptc.tx_hash()); if (it != unconfirmed_in_transfers_local.end()) { m_unconfirmed_in_transfers.insert(*it); @@ -2180,22 +2186,26 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) // read extra std::vector outs; - uint64_t sum_of_received_native_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, sum_of_received_native_outs, derivation); + r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, derivation); THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); //collect incomes for (auto& o : outs) - td.receive_indices.push_back(o.index); + { + ptc.total_balance_change[o.asset_id] += o.amount; + ptc.mtd.receive_indices.push_back(o.index); + } + bool new_multisig_spend_detected = false; //check if we have spendings - uint64_t sum_of_spent_native_coin = 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++) @@ -2223,9 +2233,11 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) if (tid != UINT64_MAX) { // own output is being spent by this input - sum_of_spent_native_coin += intk.amount; - td.spent_indices.push_back(i); + //sum_of_spent_native_coin += intk.amount; + ptc.mtd.spent_indices.push_back(i); spend_transfers.push_back(tid); + ptc.total_balance_change[currency::native_coin_asset_id] -= m_transfers[tid].amount(); + CHECK_AND_ASSERT_THROW_MES(m_transfers[tid].get_asset_id() == currency::native_coin_asset_id, "Unexpected asset id for native txin_to_key"); } } else if (in.type() == typeid(currency::txin_zc_input)) @@ -2250,8 +2262,9 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) if (tid != UINT64_MAX) { - td.spent_indices.push_back(i); + ptc.mtd.spent_indices.push_back(i); spend_transfers.push_back(tid); + ptc.total_balance_change[m_transfers[tid].asset_id] -= m_transfers[tid].amount(); } } else if (in.type() == typeid(currency::txin_multisig)) @@ -2280,47 +2293,29 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) } } - - 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)) + //do final calculations + bool has_in_transfers = false; + bool has_out_transfers = false; + for (const auto& bce : ptc.total_balance_change) { - m_unconfirmed_in_transfers[tx_hash] = tx; - if (m_unconfirmed_txs.count(tx_hash)) - continue; - - //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, sum_of_received_native_outs, td); - rise_on_transfer2(unconfirmed_wti); + if (bce.second > 0) + { + has_in_transfers = true; + } + else if (bce.second < 0) + { + has_out_transfers = true; + } } - else if (sum_of_spent_native_coin || new_multisig_spend_detected) + if (!is_tx_expired(tx, tx_expiration_ts_median) && (has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) { 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 < 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 - << ", sum_of_received_native_outs=" << sum_of_received_native_outs << ", tx_id=" << tx_hash); - } - else*/ if (new_multisig_spend_detected) - { - amount = 0; - } - else - { - 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 + make_wti_from_process_transaction_context(unconfirmed_wti, ptc); for (auto tr_index : spend_transfers) { if (tr_index > m_transfers.size()) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f8f13b3d..f12752bf 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1053,7 +1053,7 @@ private: void prepare_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att); void handle_money(const currency::block& b, const process_transaction_context& tx_process_context); - + void make_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); From 9a2371d49f032b2c562e967d6dc398a5238b07a0 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 8 Jun 2023 18:19:10 +0200 Subject: [PATCH 04/12] fixes on unconfirmed txs --- src/wallet/wallet2.cpp | 56 +++++++++++++------------ src/wallet/wallet2.h | 7 ++++ src/wallet/wallet_public_structs_defs.h | 9 ++++ 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d3bbdf4f..1f338ea3 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2264,7 +2264,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) { ptc.mtd.spent_indices.push_back(i); spend_transfers.push_back(tid); - ptc.total_balance_change[m_transfers[tid].asset_id] -= m_transfers[tid].amount(); + ptc.total_balance_change[m_transfers[tid].get_asset_id()] -= m_transfers[tid].amount(); } } else if (in.type() == typeid(currency::txin_multisig)) @@ -2273,8 +2273,8 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) auto it = m_multisig_transfers.find(multisig_id); if (it != m_multisig_transfers.end()) { - td.spent_indices.push_back(i); - r = unconfirmed_multisig_transfers_from_tx_pool.insert(std::make_pair(multisig_id, std::make_pair(tx, td))).second; + ptc.mtd.spent_indices.push_back(i); + r = unconfirmed_multisig_transfers_from_tx_pool.insert(std::make_pair(multisig_id, std::make_pair(tx, ptc.mtd))).second; if (!r) { WLT_LOG_RED("Warning: Receiving the same multisig out id from tx pool more then once: " << multisig_id, LOG_LEVEL_0); @@ -2309,12 +2309,12 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) } if (!is_tx_expired(tx, tx_expiration_ts_median) && (has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) { - m_unconfirmed_in_transfers[tx_hash] = tx; - if (m_unconfirmed_txs.count(tx_hash)) + m_unconfirmed_in_transfers[ptc.tx_hash()] = tx; + if (m_unconfirmed_txs.count(ptc.tx_hash())) continue; //prepare notification about pending transaction - wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, tx_hash); + wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, ptc.tx_hash()); make_wti_from_process_transaction_context(unconfirmed_wti, ptc); for (auto tr_index : spend_transfers) { @@ -2325,7 +2325,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) } uint32_t flags_before = m_transfers[tr_index].m_flags; m_transfers[tr_index].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; - WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers[tr_index].m_flags << ", reason: UNCONFIRMED tx: " << tx_hash); + WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers[tr_index].m_flags << ", reason: UNCONFIRMED tx: " << ptc.tx_hash()); unconfirmed_wti.selected_indicies.push_back(tr_index); } rise_on_transfer2(unconfirmed_wti); @@ -2415,7 +2415,7 @@ bool wallet2::scan_unconfirmed_outdate_tx() std::unordered_set ki_in_unconfirmed; for (auto it = m_unconfirmed_txs.begin(); it != m_unconfirmed_txs.end(); it++) { - if (it->second.is_income) + if (!it->second.has_outgoing_entries()) continue; for (auto& in : it->second.tx.vin) @@ -2424,6 +2424,10 @@ bool wallet2::scan_unconfirmed_outdate_tx() { ki_in_unconfirmed.insert(boost::get(in).k_image); } + else if (in.type() == typeid(txin_zc_input)) + { + ki_in_unconfirmed.insert(boost::get(in).k_image); + } } } @@ -2431,13 +2435,9 @@ bool wallet2::scan_unconfirmed_outdate_tx() for (size_t i = 0; i != sz; i++) { auto& t = m_transfers[i]; - - if (t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT - && !t.m_spent_height - && !static_cast(t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) - && t.m_ptx_wallet_info->m_tx.vout[t.m_internal_output_index].type() == typeid(tx_out_bare) - && boost::get(t.m_ptx_wallet_info->m_tx.vout[t.m_internal_output_index]).target.type() != typeid(txout_htlc) - ) + + if (t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT && !t.m_spent_height && !static_cast(t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) + && !t.is_htlc()) { //check if there is unconfirmed for this transfer is no longer exist? if (!ki_in_unconfirmed.count((t.m_key_image))) @@ -2447,7 +2447,6 @@ bool wallet2::scan_unconfirmed_outdate_tx() WLT_LOG_BLUE("Transfer [" << i << "] marked as unspent, flags: " << flags_before << " -> " << t.m_flags << ", reason: there is no unconfirmed tx relataed to this key image", LOG_LEVEL_0); } } - } return true; @@ -3266,19 +3265,22 @@ bool wallet2::balance(std::unordered_mapasset_id; } else { return currency::native_coin_asset_id; } } bool is_native_coin() const { return m_zc_info_ptr.get() ? (m_zc_info_ptr->asset_id == currency::native_coin_asset_id) : true; } + bool is_htlc() const { + + if (m_ptx_wallet_info->m_tx.vout[m_internal_output_index].type() == typeid(currency::tx_out_bare) && + boost::get(m_ptx_wallet_info->m_tx.vout[m_internal_output_index]).target.type() == typeid(currency::txout_htlc)) + return true; + return false; + } BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_CUSTOM(m_ptx_wallet_info, const transaction_wallet_info&, tools::wallet2::transform_ptr_to_value, tools::wallet2::transform_value_to_ptr) diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 35e841f9..201c971a 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -199,6 +199,15 @@ namespace wallet_public } return true; } + bool has_outgoing_entries() + { + for (const auto& st : subtransfers) + { + if (!st.is_income) + return true; + } + return false; + } }; struct asset_balance_entry_base From 9a18116750b4aed5c4c12d9d246dca294198b5bc Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Sun, 11 Jun 2023 00:20:11 +0200 Subject: [PATCH 05/12] wallet2.cpp got in compiled, but the rest is not yet --- src/currency_core/currency_config.h | 2 + src/gui/qt-daemon/layout | 2 +- src/wallet/wallet2.cpp | 154 ++++++++++++------------ src/wallet/wallet2.h | 49 +------- src/wallet/wallet_public_structs_defs.h | 39 +++--- 5 files changed, 109 insertions(+), 137 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index e88fc254..589af519 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -237,7 +237,9 @@ #ifndef TESTNET #define WALLET_FILE_SERIALIZATION_VERSION 160 +#define WALLET_FILE_LAST_SUPPORTED_VERSION 160 #else +#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+72) #define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+72) #endif diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 2750d12c..6aede2b4 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 2750d12c11f6063e75f6370a4382db7f0784d624 +Subproject commit 6aede2b431d688a799788cb67ad1aea9d9d87be1 diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1f338ea3..8d3914c4 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3741,7 +3741,7 @@ bool enum_container(iterator_t it_begin, iterator_t it_end, callback_t cb) //---------------------------------------------------------------------------------------------------- bool wallet2::is_consolidating_transaction(const wallet_public::wallet_transfer_info& wti) { - if (!wti.is_income) + if (wti.has_outgoing_entries()) { uint64_t income = 0; for (uint64_t r : wti.td.rcv){income += r;} @@ -3791,36 +3791,46 @@ void wallet2::get_recent_transfers_history(std::vector(ss, " ")); - ss << "]" << ","; - ss << wti.tx_hash << ","; - ss << wti.height << ","; - ss << wti.unlock_time << ","; - ss << wti.tx_blob_size << ","; - ss << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ","; - ss << "["; - std::copy(wti.remote_aliases.begin(), wti.remote_aliases.end(), std::ostream_iterator(ss, " ")); - ss << "]" << ","; - ss << (wti.is_income ? "in" : "out") << ","; - ss << (wti.is_service ? "[SERVICE]" : "") << (wti.is_mixing ? "[MIXINS]" : "") << (wti.is_mining ? "[MINING]" : "") << ","; - ss << wti.tx_type << ","; - ss << print_money(wti.fee) << ENDL; +void wallet2::wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) +{ + for(auto& subtr: wti.subtransfers) + { + ss << index << ","; + ss << epee::misc_utils::get_time_str(wti.timestamp) << ","; + ss << print_money(subtr.amount) << ","; + ss << subtr.asset_id << ","; + ss << "\"" << wti.comment << "\","; + ss << "["; + std::copy(wti.remote_addresses.begin(), wti.remote_addresses.end(), std::ostream_iterator(ss, " ")); + ss << "]" << ","; + ss << wti.tx_hash << ","; + ss << wti.height << ","; + ss << wti.unlock_time << ","; + ss << wti.tx_blob_size << ","; + ss << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ","; + ss << "["; + std::copy(wti.remote_aliases.begin(), wti.remote_aliases.end(), std::ostream_iterator(ss, " ")); + ss << "]" << ","; + ss << (subtr.is_income ? "in" : "out") << ","; + ss << (wti.is_service ? "[SERVICE]" : "") << (wti.is_mixing ? "[MIXINS]" : "") << (wti.is_mining ? "[MINING]" : "") << ","; + ss << wti.tx_type << ","; + ss << print_money(wti.fee) << ENDL; + } + }; void wallet2::wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) { - ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t" - << epee::misc_utils::get_time_str(wti.timestamp) << "\t" - << print_money(wti.amount) << "\t" - << print_money(wti.fee) << "\t" - << wti.remote_addresses << "\t" - << wti.comment << ENDL; + for (auto& subtr : wti.subtransfers) + { + ss << (subtr.is_income ? "[INC]" : "[OUT]") << "\t" + << epee::misc_utils::get_time_str(wti.timestamp) << "\t" + << print_money(subtr.amount) << "\t" + << subtr.asset_id << "\t" + << print_money(wti.fee) << "\t" + << wti.remote_addresses << "\t" + << wti.comment << ENDL; + } }; void wallet2::wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) @@ -3851,7 +3861,7 @@ void wallet2::export_transaction_history(std::ostream& ss, const std::string& fo else { //csv by default - ss << "N, Date, Amount, Comment, Address, ID, Height, Unlock timestamp, Tx size, Alias, PaymentID, In/Out, Flags, Type, Fee" << ENDL; + ss << "N, Date, Amount, AssetID, Comment, Address, ID, Height, Unlock timestamp, Tx size, Alias, PaymentID, In/Out, Flags, Type, Fee" << ENDL; } @@ -3913,7 +3923,7 @@ void wallet2::get_mining_history(wallet_public::mining_history& hist, uint64_t t if (currency::is_coinbase(tr.tx) && tr.tx.vin.size() == 2 && tr.timestamp > timestamp_from) { tools::wallet_public::mining_history_entry mhe = AUTO_VAL_INIT(mhe); - mhe.a = tr.amount; + mhe.a = tr.get_native_income_amount(); mhe.t = tr.timestamp; mhe.h = tr.height; hist.mined_entries.push_back(mhe); @@ -4893,8 +4903,7 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele } WLT_LOG_GREEN(m_money_expirations.back().selected_transfers.size() << " transfer(s) added to expiration list:" << ENDL << "index amount flags tx hash" << ENDL << - ss.str() << - "change_amount: " << print_money_brief(change_amount) << ", expire(s) at: " << expiration, LOG_LEVEL_0); + ss.str() << ", expire(s) at: " << expiration, LOG_LEVEL_0); } //---------------------------------------------------------------------------------------------------- void wallet2::remove_transfer_from_expiration_list(uint64_t transfer_index) @@ -5156,7 +5165,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal selected_transfers = ftp.selected_transfers; currency::finalized_tx finalize_result = AUTO_VAL_INIT(finalize_result); finalize_transaction(ftp, finalize_result, false); - add_transfers_to_expiration_list(selected_transfers, proposal_detais.expiration_time, 0, currency::null_hash); + add_transfers_to_expiration_list(selected_transfers, proposal_detais.expiration_time, currency::null_hash); //wrap it all proposal.tx_template = finalize_result.tx; @@ -5187,8 +5196,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo const transaction& tx = proposal.tx_template; crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); std::vector outs; - uint64_t tx_money_got_in_outs = 0; - bool r = lookup_acc_outs(m_account.get_keys(), tx, outs, tx_money_got_in_outs, derivation); + bool r = lookup_acc_outs(m_account.get_keys(), tx, outs, derivation); THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to lookup_acc_outs for tx: " << get_transaction_hash(tx)); if (!outs.size()) @@ -6109,23 +6117,6 @@ bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_ return false; } //---------------------------------------------------------------------------------------------------- -void wallet2::wipeout_extra_if_needed(std::vector& transfer_history) -{ - WLT_LOG_L0("Processing [wipeout_extra_if_needed]..."); - for (auto it = transfer_history.begin(); it != transfer_history.end(); it++ ) - { - if (it->height > 638000) - { - it->remote_addresses.clear(); - if (is_watch_only() && !it->is_income) - { - it->comment.clear(); - } - } - } - WLT_LOG_L0("Processing [wipeout_extra_if_needed] DONE"); -} -//---------------------------------------------------------------------------------------------------- bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) { if (!td.is_spendable()) @@ -6202,34 +6193,44 @@ void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, PROFILE_FUNC("wallet2::add_sent_unconfirmed_tx"); wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, currency::get_transaction_hash(tx)); - //unconfirmed_wti.tx = tx; + unconfirmed_wti.tx = tx; unconfirmed_wti.remote_addresses = recipients; for (auto addr : recipients) unconfirmed_wti.remote_aliases.push_back(get_alias_for_address(addr)); - unconfirmed_wti.is_income = false; - unconfirmed_wti.selected_indicies = selected_indicies; - unconfirmed_wti.asset_id = null_pkey; - uint64_t native_coin_change_amount = 0; - uint64_t native_coin_inputs_amount = 0; + process_transaction_context tx_process_context(tx); + +// for (const auto& sel_i : selected_indicies) +// { +// crypto::public_key asset_id = m_transfers[sel_i].get_asset_id(); +// if (asset_id == currency::native_coin_asset_id) +// { +// tx_process_context.spent_own_native_inputs = true; +// } +// tx_process_context.total_balance_change[asset_id] -= m_transfers[sel_i].amount(); +// } + + + for (auto& d : splitted_dsts) + { + if (d.addr.size() && + d.addr.back().spend_public_key == m_account.get_keys().account_address.spend_public_key && + d.addr.back().view_public_key == m_account.get_keys().account_address.view_public_key) + { + unconfirmed_wti.td.rcv.push_back(d.amount); + tx_process_context.total_balance_change[d.asset_id] += d.amount; + } + } + + unconfirmed_wti.selected_indicies = selected_indicies; + // TODO @#@# potential issue: one tx may have different asset_id's in INs or OUTs // but only one asset_id is associated with a transfer atm // possible solution: make a transfer item for each asset_id in tx -- sowle - for (auto& d : splitted_dsts) - { - if (d.addr.size() && - d.addr.back().spend_public_key == m_account.get_keys().account_address.spend_public_key && - d.addr.back().view_public_key == m_account.get_keys().account_address.view_public_key) - { - unconfirmed_wti.td.rcv.push_back(d.amount); - WLT_CHECK_AND_ASSERT_MES(unconfirmed_wti.asset_id == null_pkey || unconfirmed_wti.asset_id == d.asset_id, (void)0, "TODO: BAD case with asset_id"); - unconfirmed_wti.asset_id = d.asset_id; - if (d.asset_id == native_coin_asset_id) - native_coin_change_amount += d.amount; - } - } + // RE: TODO - discuss with @sowl -- zoidberg + // check all inputs for spending (compare key images) //scan key images for (auto& i : tx.vin) { @@ -6243,15 +6244,18 @@ void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "[read_money_transfer2_details_from_tx]Index out of range for key image in tx: " << get_transaction_hash(tx)); unconfirmed_wti.td.spn.push_back(m_transfers[it->second].amount()); - WLT_CHECK_AND_ASSERT_MES(unconfirmed_wti.asset_id == null_pkey || unconfirmed_wti.asset_id == m_transfers[it->second].get_asset_id(), (void)0, "TODO: BAD case with asset_id"); - unconfirmed_wti.asset_id = m_transfers[it->second].get_asset_id(); - if (unconfirmed_wti.asset_id == native_coin_asset_id) - native_coin_inputs_amount += m_transfers[it->second].amount(); + + crypto::public_key asset_id = m_transfers[it->second].get_asset_id(); + if (asset_id == currency::native_coin_asset_id) + { + tx_process_context.spent_own_native_inputs = true; + } + tx_process_context.total_balance_change[asset_id] -= m_transfers[it->second].amount(); } } } - prepare_wti(unconfirmed_wti, 0, m_core_runtime_config.get_core_time(), tx, native_coin_inputs_amount - (native_coin_change_amount + get_tx_fee(tx)), money_transfer2_details()); + prepare_wti(unconfirmed_wti, tx_process_context); rise_on_transfer2(unconfirmed_wti); } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f3c3ae28..c43286da 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -571,7 +571,7 @@ namespace tools size_t sub_i = 0; uint64_t height = 0; uint64_t timestamp = 0; - std::map total_balance_change; + std::unordered_map total_balance_change; std::vector recipients; std::vector remote_aliases; @@ -831,10 +831,9 @@ namespace tools WLT_LOG_MAGENTA("Wallet file truncated due to WALLET_FILE_SERIALIZATION_VERSION is more then curren build", LOG_LEVEL_0); return; } - - if (ver < 149) + if(ver < WALLET_FILE_LAST_SUPPORTED_VERSION) { - WLT_LOG_MAGENTA("Wallet file truncated due to old version. ver: " << ver << ", WALLET_FILE_SERIALIZATION_VERSION=" << WALLET_FILE_SERIALIZATION_VERSION, LOG_LEVEL_0); + WLT_LOG_MAGENTA("Wallet file truncated due to ver(" << ver << ") is less then WALLET_FILE_LAST_SUPPORTED_VERSION", LOG_LEVEL_0); return; } @@ -854,29 +853,9 @@ namespace tools } } //convert from old version - if (ver < 150) - { - WLT_LOG_MAGENTA("Converting blockchain into a short form...", LOG_LEVEL_0); - std::vector old_blockchain; - a & old_blockchain; - uint64_t count = 0; - for (auto& h : old_blockchain) - { - m_chain.push_new_block_id(h, count); - count++; - } - WLT_LOG_MAGENTA("Converting done", LOG_LEVEL_0); - } - else - { - a & m_chain; - a & m_minimum_height; - } - - // v151: m_amount_gindex_to_transfer_id added - if (ver >= 151) - a & m_amount_gindex_to_transfer_id; - + a & m_chain; + a & m_minimum_height; + a & m_amount_gindex_to_transfer_id; a & m_transfers; a & m_multisig_transfers; a & m_key_images; @@ -890,28 +869,13 @@ namespace tools a & m_pending_key_images; a & m_tx_keys; a & m_last_pow_block_h; - - //after processing - if (ver < 152) - { - wipeout_extra_if_needed(m_transfer_history); - } - - if (ver < 153) - return; - a & m_htlcs; a & m_active_htlcs; a & m_active_htlcs_txid; - - if (ver < 154) - return; - a & m_own_asset_descriptors; a & m_custom_assets; } - void wipeout_extra_if_needed(std::vector& transfer_history); bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count); bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count); uint64_t select_indices_for_transfer(std::vector& ind, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count); @@ -1339,7 +1303,6 @@ namespace boost inline void serialize(Archive& a, tools::wallet2::expiration_entry_info& x, const boost::serialization::version_type ver) { a & x.expiration_time; - a & x.change_amount; a & x.selected_transfers; a & x.related_tx_id; } diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 201c971a..effc3b8d 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -165,32 +165,25 @@ namespace wallet_public END_KV_SERIALIZE_MAP() BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(key_offsets) // referring_input - BOOST_SERIALIZE(k_image) - BOOST_SERIALIZE(etc_details) + BOOST_SERIALIZE(timestamp) BOOST_SERIALIZE(tx_hash) BOOST_SERIALIZE(height) - BOOST_SERIALIZE(unlock_time) BOOST_SERIALIZE(tx_blob_size) BOOST_SERIALIZE(payment_id) - BOOST_SERIALIZE(comment) - BOOST_SERIALIZE(timestamp) - BOOST_SERIALIZE(td) - BOOST_SERIALIZE(fee) - BOOST_SERIALIZE(is_service) - BOOST_SERIALIZE(is_mixing) - BOOST_SERIALIZE(is_mining) - BOOST_SERIALIZE(tx_type) - BOOST_SERIALIZE(show_sender) - BOOST_SERIALIZE(contract) - BOOST_SERIALIZE(service_entries) - BOOST_SERIALIZE(transfer_internal_index) BOOST_SERIALIZE(remote_addresses) + BOOST_SERIALIZE(td) + BOOST_SERIALIZE(tx) BOOST_SERIALIZE(remote_aliases) + BOOST_SERIALIZE(comment) + BOOST_SERIALIZE(contract) + BOOST_SERIALIZE(selected_indicies) + BOOST_SERIALIZE(marketplace_entries) + BOOST_SERIALIZE(unlock_time) + BOOST_SERIALIZE(service_entries) BOOST_SERIALIZE(subtransfers) END_BOOST_SERIALIZATION() - bool is_income_mode_encryption() + bool is_income_mode_encryption() const { for (const auto& st : subtransfers) { @@ -199,7 +192,7 @@ namespace wallet_public } return true; } - bool has_outgoing_entries() + bool has_outgoing_entries() const { for (const auto& st : subtransfers) { @@ -208,8 +201,18 @@ namespace wallet_public } return false; } + uint64_t get_native_income_amount() const + { + for (const auto& st : subtransfers) + { + if (st.asset_id == currency::native_coin_asset_id && st.is_income) + return st.amount; + } + return 0; + } }; + struct asset_balance_entry_base { uint64_t total = 0; From c48f840f686a0e35343d11d4b117fb4f73b08038 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 13 Jun 2023 00:16:46 +0200 Subject: [PATCH 06/12] fixes over renect_history refactoring(tests still broken) --- src/currency_core/currency_format_utils.cpp | 5 ++--- src/wallet/wallet2.cpp | 6 ------ src/wallet/wallet2_escrow.cpp | 2 +- src/wallet/wallet_id_adapter.h | 4 ++-- src/wallet/wallet_public_structs_defs.h | 24 ++++++++++++++++++--- src/wallet/wallet_rpc_server.cpp | 7 +++--- tests/core_tests/atomic_tests.cpp | 2 +- tests/core_tests/chaingen_helpers.h | 19 ++++++++++++++++ tests/core_tests/escrow_wallet_tests.cpp | 2 +- tests/core_tests/hard_fork_2.cpp | 10 ++++----- tests/core_tests/transaction_tests.cpp | 2 +- tests/core_tests/wallet_tests.cpp | 8 +++---- tests/core_tests/wallet_tests.h | 2 +- tests/core_tests/wallet_tests_basic.h | 23 ++++++++++++++++---- 14 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 7303fb06..d1606992 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1664,10 +1664,10 @@ namespace currency txin_htlc htlc_in = AUTO_VAL_INIT(htlc_in); x.tx_type = get_tx_type_ex(x.tx, htlc_out, htlc_in); - if(x.tx_type == GUI_TX_TYPE_HTLC_DEPOSIT && x.is_income == true) + if(x.tx_type == GUI_TX_TYPE_HTLC_DEPOSIT && !x.has_outgoing_entries()) { //need to override amount - x.amount = htlc_out.amount; + x.get_native_income_amount() = htlc_out.amount; } } @@ -2941,7 +2941,6 @@ namespace currency if (is_out_to_acc(acc.account_address, boost::get(o.target), derivation, offset)) { outs.emplace_back(offset, o.amount); - money_transfered += o.amount; } return true; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8d3914c4..3a693184 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6224,12 +6224,6 @@ void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, unconfirmed_wti.selected_indicies = selected_indicies; - - // TODO @#@# potential issue: one tx may have different asset_id's in INs or OUTs - // but only one asset_id is associated with a transfer atm - // possible solution: make a transfer item for each asset_id in tx -- sowle - // RE: TODO - discuss with @sowl -- zoidberg - // check all inputs for spending (compare key images) //scan key images for (auto& i : tx.vin) diff --git a/src/wallet/wallet2_escrow.cpp b/src/wallet/wallet2_escrow.cpp index 12c46142..2efab94c 100644 --- a/src/wallet/wallet2_escrow.cpp +++ b/src/wallet/wallet2_escrow.cpp @@ -55,7 +55,7 @@ bool wallet2::validate_escrow_proposal(const wallet_public::wallet_transfer_info // (2/5) extra decrypted_items.clear(); - bool r = decrypt_payload_items(wti.is_income, prop.tx_template, m_account.get_keys(), decrypted_items); + bool r = decrypt_payload_items(wti.is_income_mode_encryption(), prop.tx_template, m_account.get_keys(), decrypted_items); LOC_CHK(r, "failed to decrypt payload items in proposal tx"); currency::tx_service_attachment tsa = AUTO_VAL_INIT(tsa); diff --git a/src/wallet/wallet_id_adapter.h b/src/wallet/wallet_id_adapter.h index e794795f..73b3627b 100644 --- a/src/wallet/wallet_id_adapter.h +++ b/src/wallet/wallet_id_adapter.h @@ -12,7 +12,7 @@ class i_backend_wallet_callback { public: virtual void on_new_block(size_t wallet_id, uint64_t /*height*/, const currency::block& /*block*/) {} - virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) {} + virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) {} virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/) {} virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/) {} virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti) {} @@ -32,7 +32,7 @@ struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback virtual void on_new_block(uint64_t height, const currency::block& block) { m_pbackend->on_new_block(m_wallet_id, height, block); } - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { m_pbackend->on_transfer2(m_wallet_id, wti, balances, total_mined); } virtual void on_pos_block_found(const currency::block& wti) { diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index effc3b8d..23529d13 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -91,9 +91,9 @@ namespace wallet_public struct wallet_sub_transfer_info { - uint64_t amount; - bool is_income; - crypto::public_key asset_id; // not blinded, not premultiplied by 1/8 + uint64_t amount = 0; + bool is_income = false; + crypto::public_key asset_id = currency::native_coin_asset_id; // not blinded, not premultiplied by 1/8 BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) @@ -210,6 +210,24 @@ namespace wallet_public } return 0; } + uint64_t& get_native_income_amount() + { + for (auto& st : subtransfers) + { + if (st.asset_id == currency::native_coin_asset_id) + if (st.is_income) + { + return st.amount; + } + else + { + throw std::runtime_error("Unexpected wallet_transfer_info: native is not income type"); + } + } + subtransfers.push_back(wallet_sub_transfer_info()); + subtransfers.back().is_income = true; + return subtransfers.back().amount; + } }; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 6ea7b2e4..87f90a0c 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -688,10 +688,11 @@ namespace tools } } - if (wti.is_income && req.in) + bool has_outgoing = wti.has_outgoing_entries(); + if (!has_outgoing && req.in) res.in.push_back(wti); - if (!wti.is_income && req.out) + if (has_outgoing && req.out) res.out.push_back(wti); return true; // continue @@ -701,7 +702,7 @@ namespace tools if (req.pool) { w.get_wallet()->enumerate_unconfirmed_transfers([&](const wallet_public::wallet_transfer_info& wti) -> bool { - if ((wti.is_income && req.in) || (!wti.is_income && req.out)) + if ((!wti.has_outgoing_entries() && req.in) || (wti.has_outgoing_entries() && req.out)) res.pool.push_back(wti); return true; // continue }); diff --git a/tests/core_tests/atomic_tests.cpp b/tests/core_tests/atomic_tests.cpp index 41382a51..f04d984a 100644 --- a/tests/core_tests/atomic_tests.cpp +++ b/tests/core_tests/atomic_tests.cpp @@ -24,7 +24,7 @@ using namespace currency; struct wallet_tests_callback_handler : public tools::i_wallet2_callback { - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { all_wtis.push_back(wti); } diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index b95613af..82208abd 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -316,3 +316,22 @@ inline bool put_alias_via_tx_to_list(const currency::hard_forks_descriptor& hf, return true; } + +//--------------------------------------------------------------- +namespace currency +{ + //this lookup_acc_outs overload is mostly for backward compatibility for tests, ineffective from performance perspective, should not be used in wallet + inline bool lookup_acc_outs(const currency::account_keys& acc, const currency::transaction& tx, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation) + { + sum_of_native_outs = 0; + bool res = currency::lookup_acc_outs(acc, tx, outs, derivation); + for (const auto& o : outs) + { + if (o.asset_id == currency::native_coin_asset_id) + { + sum_of_native_outs += o.amount; + } + } + return res; + } +} diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index 6cee1610..49521201 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -17,7 +17,7 @@ using namespace currency; struct wallet_tests_callback_handler : public tools::i_wallet2_callback { - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { all_wtis.push_back(wti); } diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 8f434d2b..3f5b3c83 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -140,7 +140,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons size_t callback_counter = 0; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); @@ -234,7 +234,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(2), "incorrect wti.amount = " << print_money_brief(wti.amount)); CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); @@ -367,7 +367,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); @@ -409,7 +409,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(4), "incorrect wti.amount = " << print_money_brief(wti.amount)); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); @@ -1003,7 +1003,7 @@ bool hard_fork_2_awo_wallets_basic_test::c1(currency::core& c, size bool callback_called = false; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&callback_called](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&callback_called](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { callback_called = true; return true; } diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index cd8643ca..150ec14a 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -10,7 +10,7 @@ #include "currency_core/account.h" #include "currency_core/currency_format_utils.h" #include "misc_language.h" - +#include "chaingen_helpers.h" using namespace currency; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 929b8d50..306b01d0 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1598,7 +1598,7 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e return true; } -void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) +void gen_wallet_decrypted_attachments::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { m_on_transfer2_called = true; //try { @@ -1831,7 +1831,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ uint64_t biggest_alias_reward = get_alias_coast_from_fee("a", TESTS_DEFAULT_FEE); std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { return std::count(wti.remote_aliases.begin(), wti.remote_aliases.end(), "minerminer") == 1 && wti.amount == biggest_alias_reward; } @@ -3307,7 +3307,7 @@ bool wallet_unconfimed_tx_balance::c1(currency::core& c, size_t ev_index, const bool callback_is_ok = false; // this callback will ba called from within wallet2::transfer() below std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&callback_is_ok](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool + [&callback_is_ok](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { CHECK_AND_ASSERT_MES(balance == MK_TEST_COINS(70), false, "invalid balance: " << print_money_brief(balance)); CHECK_AND_ASSERT_MES(unlocked_balance == MK_TEST_COINS(50), false, "invalid unlocked_balance: " << print_money_brief(unlocked_balance)); @@ -3457,7 +3457,7 @@ bool wallet_sending_to_integrated_address::c1(currency::core& c, size_t ev_index bool callback_succeded = false; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( - [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { LOG_PRINT_YELLOW("on_transfer: " << print_money_brief(wti.amount) << " pid len: " << wti.payment_id.size() << " remote addr: " << (wti.remote_addresses.size() > 0 ? wti.remote_addresses[0] : ""), LOG_LEVEL_0); if (wti.payment_id.empty()) return true; // skip another outputs diff --git a/tests/core_tests/wallet_tests.h b/tests/core_tests/wallet_tests.h index b5368fb1..08720808 100644 --- a/tests/core_tests/wallet_tests.h +++ b/tests/core_tests/wallet_tests.h @@ -110,7 +110,7 @@ struct gen_wallet_decrypted_attachments : public wallet_test, virtual public too bool generate(std::vector& events) const; // intrface tools::i_wallet2_callback - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override; + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override; private: mutable bool m_on_transfer2_called; diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index ef044c48..6fc66a99 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -48,6 +48,17 @@ protected: std::shared_ptr m_core_proxy; }; + +const tools::wallet_public::asset_balance_entry get_native_balance_entry(const std::list& balances) +{ + for (const auto& b : balances) + { + if (b.asset_info.asset_id == currency::native_coin_asset_id) + return b; + } + return tools::wallet_public::asset_balance_entry(); +} + // wallet callback helper to check balance in wallet callbacks // see escrow_balance test for usage example struct wallet_callback_balance_checker : public tools::i_wallet2_callback @@ -62,8 +73,12 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback m_called = false; } - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override { + tools::wallet_public::asset_balance_entry native_balance = get_native_balance_entry(balances); + uint64_t balance = native_balance.total; + uint64_t unlocked_balance = native_balance.unlocked; + m_called = true; m_result = false; CHECK_AND_ASSERT_MES(m_balance == UINT64_MAX || balance == m_balance, (void)(0), m_label << " balance is incorrect: " << currency::print_money_brief(balance) << ", expected: " << currency::print_money_brief(m_balance)); @@ -94,11 +109,11 @@ struct wallet_callback_balance_checker : public tools::i_wallet2_callback struct wlt_lambda_on_transfer2_wrapper : public tools::i_wallet2_callback { - typedef std::function&, uint64_t)> Func; + typedef std::function&, uint64_t)> Func; wlt_lambda_on_transfer2_wrapper(Func callback) : m_result(false), m_callback(callback) {} - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override { - m_result = m_callback(wti, balance, unlocked_balance, total_mined); + m_result = m_callback(wti, balances, total_mined); } bool m_result; Func m_callback; From b744dfb79b6c11464bebd2571d241e76a90915eb Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 13 Jun 2023 23:06:55 +0200 Subject: [PATCH 07/12] all tests compilation fixed(still a lot of broken tests) --- src/wallet/wallet_public_structs_defs.h | 18 ++++++++++++++++++ tests/core_tests/chaingen.cpp | 14 +------------- tests/core_tests/chaingen.h | 2 +- tests/core_tests/chaingen_helpers.h | 18 ++++++++++++++++++ tests/core_tests/escrow_wallet_tests.cpp | 4 ++-- tests/core_tests/hard_fork_2.cpp | 8 ++++---- tests/core_tests/transaction_tests.cpp | 4 ++-- tests/core_tests/wallet_tests.cpp | 10 +++++++--- tests/core_tests/wallet_tests_basic.h | 2 +- 9 files changed, 54 insertions(+), 26 deletions(-) diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 23529d13..279fc41a 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -210,6 +210,24 @@ namespace wallet_public } return 0; } + uint64_t get_native_amount() const + { + for (const auto& st : subtransfers) + { + if (st.asset_id == currency::native_coin_asset_id ) + return st.amount; + } + return 0; + } + bool get_native_is_income() const + { + for (const auto& st : subtransfers) + { + if (st.asset_id == currency::native_coin_asset_id) + return st.is_income; + } + return false; + } uint64_t& get_native_income_amount() { for (auto& st : subtransfers) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 45b51919..1990ead4 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -2067,7 +2067,7 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, return true; } -bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result /* = true */, uint64_t* p_change /* = nullptr */) +bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result) { std::deque transfers; w.get_transfers(transfers); @@ -2078,18 +2078,6 @@ bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_ if (td.m_flags == (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION)) result += td.amount(); } - if (substruct_change_from_result || p_change != nullptr) - { - const std::list& ee = w.get_expiration_entries(); - for (auto &e : ee) - { - CHECK_AND_ASSERT_MES(result >= e.change_amount, false, "wrong transfers: result: " << print_money(result) << " is expected to be NOT LESS than change_amount: " << print_money(e.change_amount)); - if (substruct_change_from_result) - result -= e.change_amount; - if (p_change != nullptr) - *p_change += e.change_amount; - } - } return true; } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 936e422a..6ab7b76b 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -724,7 +724,7 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, const std::vector& attachments = empty_attachment, const std::vector& extra = empty_extra); -bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result = true, uint64_t* p_change = nullptr); +bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result); bool check_wallet_balance_blocked_for_escrow(const tools::wallet2& w, const char* wallet_name, uint64_t expected_amount); bool refresh_wallet_and_check_balance(const char* intro_log_message, const char* wallet_name, std::shared_ptr wallet, uint64_t expected_total, bool print_transfers = false, diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 82208abd..b984fde7 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -323,6 +323,7 @@ namespace currency //this lookup_acc_outs overload is mostly for backward compatibility for tests, ineffective from performance perspective, should not be used in wallet inline bool lookup_acc_outs(const currency::account_keys& acc, const currency::transaction& tx, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation) { + outs.clear(); sum_of_native_outs = 0; bool res = currency::lookup_acc_outs(acc, tx, outs, derivation); for (const auto& o : outs) @@ -334,4 +335,21 @@ namespace currency } return res; } + + //this lookup_acc_outs overload is mostly for backward compatibility for tests, ineffective from performance perspective, should not be used in wallet + inline bool lookup_acc_outs(const currency::account_keys& acc, const currency::transaction& tx, const crypto::public_key& /*tx_onetime_pubkey*/, std::vector& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation) + { + sum_of_native_outs = 0; + bool res = currency::lookup_acc_outs(acc, tx, outs, derivation); + for (const auto& o : outs) + { + if (o.asset_id == currency::native_coin_asset_id) + { + sum_of_native_outs += o.amount; + } + } + return res; + } + + } diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index 49521201..472a2ab5 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -2601,7 +2601,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in crypto::hash contract_id = contracts.begin()->first; uint64_t alice_blocked_transfers_sum = 0; - CHECK_AND_ASSERT_MES(estimate_wallet_balance_blocked_for_escrow(*alice_wlt.get(), alice_blocked_transfers_sum, false), false, ""); + CHECK_AND_ASSERT_MES(estimate_wallet_balance_blocked_for_escrow(*alice_wlt.get(), alice_blocked_transfers_sum), false, ""); // mine a block, containing escrow proposal tx CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2622,7 +2622,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in bob_wlt->accept_proposal(contract_id, TESTS_DEFAULT_FEE); uint64_t bob_blocked_transfers_sum = 0; - CHECK_AND_ASSERT_MES(estimate_wallet_balance_blocked_for_escrow(*bob_wlt.get(), bob_blocked_transfers_sum, false), false, ""); + CHECK_AND_ASSERT_MES(estimate_wallet_balance_blocked_for_escrow(*bob_wlt.get(), bob_blocked_transfers_sum), false, ""); // mine a block containing contract acceptance CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); diff --git a/tests/core_tests/hard_fork_2.cpp b/tests/core_tests/hard_fork_2.cpp index 3f5b3c83..92d2d130 100644 --- a/tests/core_tests/hard_fork_2.cpp +++ b/tests/core_tests/hard_fork_2.cpp @@ -235,7 +235,7 @@ bool hard_fork_2_tx_payer_in_wallet::c1(currency::core& c, size_t ev_index, cons std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(2), "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_THROW_MES(wti.get_native_amount() == MK_TEST_COINS(2), "incorrect wti.amount = " << print_money_brief(wti.get_native_amount())); CHECK_AND_ASSERT_THROW_MES(wti.show_sender, "show_sender is false"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 1, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); @@ -368,7 +368,7 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); + CHECK_AND_ASSERT_THROW_MES(!wti.get_native_is_income(), "wti.is_income is " << wti.get_native_is_income()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), "wti.remote_addresses.back is incorrect"); @@ -410,8 +410,8 @@ bool hard_fork_2_tx_receiver_in_wallet::c1(currency::core& c, size_t ev_index, c std::shared_ptr l2(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { - CHECK_AND_ASSERT_THROW_MES(!wti.is_income, "wti.is_income is " << wti.is_income); - CHECK_AND_ASSERT_THROW_MES(wti.amount == MK_TEST_COINS(4), "incorrect wti.amount = " << print_money_brief(wti.amount)); + CHECK_AND_ASSERT_THROW_MES(!wti.get_native_is_income(), "wti.is_income is " << wti.get_native_is_income()); + CHECK_AND_ASSERT_THROW_MES(wti.get_native_amount() == MK_TEST_COINS(4), "incorrect wti.amount = " << print_money_brief(wti.get_native_amount())); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.size() == 2, "incorrect wti.remote_addresses.size() = " << wti.remote_addresses.size()); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.front() == m_accounts[MINER_ACC_IDX].get_public_address_str(), "wti.remote_addresses.front is incorrect"); CHECK_AND_ASSERT_THROW_MES(wti.remote_addresses.back() == m_accounts[BOB_ACC_IDX].get_public_address_str(), "wti.remote_addresses.back is incorrect"); diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 150ec14a..7ad10ec1 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -116,12 +116,12 @@ bool test_transaction_generation_and_ring_signature() std::vector outs; uint64_t money = 0; crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - r = lookup_acc_outs(rv_acc.get_keys(), tx_rc1, get_tx_pub_key_from_extra(tx_rc1), outs, money, derivation); + r = lookup_acc_outs(rv_acc.get_keys(), tx_rc1, outs, money, derivation); CHECK_AND_ASSERT_MES(r, false, "failed to lookup_acc_outs"); CHECK_AND_ASSERT_MES(td.amount == money, false, "wrong money amount in new transaction"); money = 0; derivation = AUTO_VAL_INIT(derivation); - r = lookup_acc_outs(rv_acc2.get_keys(), tx_rc1, get_tx_pub_key_from_extra(tx_rc1), outs, money, derivation); + r = lookup_acc_outs(rv_acc2.get_keys(), tx_rc1, outs, money, derivation); CHECK_AND_ASSERT_MES(r, false, "failed to lookup_acc_outs"); CHECK_AND_ASSERT_MES(0 == money, false, "wrong money amount in new transaction"); return true; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 306b01d0..b4540fcf 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1833,7 +1833,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { return std::count(wti.remote_aliases.begin(), wti.remote_aliases.end(), "minerminer") == 1 && - wti.amount == biggest_alias_reward; + wti.get_native_amount() == biggest_alias_reward; } )); alice_wlt->callback(l); @@ -3309,6 +3309,10 @@ bool wallet_unconfimed_tx_balance::c1(currency::core& c, size_t ev_index, const std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [&callback_is_ok](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { + tools::wallet_public::asset_balance_entry abe = get_native_balance_entry(balances); + uint64_t balance = abe.total; + uint64_t unlocked_balance = abe.unlocked; + CHECK_AND_ASSERT_MES(balance == MK_TEST_COINS(70), false, "invalid balance: " << print_money_brief(balance)); CHECK_AND_ASSERT_MES(unlocked_balance == MK_TEST_COINS(50), false, "invalid unlocked_balance: " << print_money_brief(unlocked_balance)); CHECK_AND_ASSERT_MES(total_mined == 0, false, "invalid total_mined: " << print_money_brief(total_mined)); @@ -3458,7 +3462,7 @@ bool wallet_sending_to_integrated_address::c1(currency::core& c, size_t ev_index bool callback_succeded = false; std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [&](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { - LOG_PRINT_YELLOW("on_transfer: " << print_money_brief(wti.amount) << " pid len: " << wti.payment_id.size() << " remote addr: " << (wti.remote_addresses.size() > 0 ? wti.remote_addresses[0] : ""), LOG_LEVEL_0); + LOG_PRINT_YELLOW("on_transfer: " << print_money_brief(wti.get_native_amount()) << " pid len: " << wti.payment_id.size() << " remote addr: " << (wti.remote_addresses.size() > 0 ? wti.remote_addresses[0] : ""), LOG_LEVEL_0); if (wti.payment_id.empty()) return true; // skip another outputs CHECK_AND_ASSERT_MES(wti.payment_id == payment_id, false, "incorrect payment id"); @@ -3669,7 +3673,7 @@ bool wallet_spend_form_auditable_and_track::c1(currency::core& c, size_t ev_inde r = false; bool r_comment = false; bob_wlt->enumerate_transfers_history([&](const tools::wallet_public::wallet_transfer_info& wti) { - if (wti.amount == MK_TEST_COINS(5)) + if (wti.get_native_amount() == MK_TEST_COINS(5)) { r_comment = (wti.comment == m_comment); if (!r_comment) diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 6fc66a99..0329e0a2 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -49,7 +49,7 @@ protected: }; -const tools::wallet_public::asset_balance_entry get_native_balance_entry(const std::list& balances) +inline const tools::wallet_public::asset_balance_entry get_native_balance_entry(const std::list& balances) { for (const auto& b : balances) { From 3b190388b2db659f077056bedfcb85f8db7e0d43 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 15 Jun 2023 23:55:22 +0200 Subject: [PATCH 08/12] refactoring of wallet_transfer_info and unconfirmed balance calculations --- src/currency_core/currency_config.h | 4 +- .../currency_format_utils_transactions.cpp | 2 + src/wallet/wallet2.cpp | 467 ++++++++---------- src/wallet/wallet2.h | 28 +- src/wallet/wallet_public_structs_defs.h | 41 +- 5 files changed, 258 insertions(+), 284 deletions(-) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 589af519..b69e86ab 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -239,8 +239,8 @@ #define WALLET_FILE_SERIALIZATION_VERSION 160 #define WALLET_FILE_LAST_SUPPORTED_VERSION 160 #else -#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+72) -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+72) +#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+73) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+73) #endif #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index 95bb4cdd..2b5850fe 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -25,6 +25,8 @@ namespace currency //------------------------------------------------------------------ bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median) { + if (expiration_ts_median == 0) + return false; /// tx expiration condition (tx is ok if the following is true) /// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW) uint64_t expiration_time = get_tx_expiration_time(tx); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3a693184..898cf5d8 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -81,7 +81,7 @@ namespace tools m_core_runtime_config = currency::get_default_core_runtime_config(); } //--------------------------------------------------------------- - uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td) + uint64_t wallet2::get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const wallet_public::employed_tx_entries& td) { uint64_t max_unlock_time = 0; // etc_tx_details_expiration_time have priority over etc_tx_details_expiration_time2 @@ -96,8 +96,9 @@ namespace tools CHECK_AND_ASSERT_THROW_MES(ut2.unlock_time_array.size() == tx.vout.size(), "Internal error: wrong tx transfer details: ut2.unlock_time_array.size()" << ut2.unlock_time_array.size() << " is not equal transaction outputs vector size=" << tx.vout.size()); - for (auto ri : td.receive_indices) + for (auto r : td.receive) { + uint64_t ri = r.index; CHECK_AND_ASSERT_THROW_MES(ri < tx.vout.size(), "Internal error: wrong tx transfer details: reciev index=" << ri << " is greater than transaction outputs vector " << tx.vout.size()); VARIANT_SWITCH_BEGIN(tx.vout[ri]); VARIANT_CASE_CONST(tx_out_bare, o) @@ -114,32 +115,6 @@ namespace tools return max_unlock_time; } //---------------------------------------------------------------------------------------------------- -void wallet2::fill_transfer_details(const currency::transaction& tx, const tools::money_transfer2_details& td, tools::wallet_public::wallet_transfer_info_details& res_td) const -{ - PROFILE_FUNC("wallet2::fill_transfer_details"); - for (auto si : td.spent_indices) - { - WLT_CHECK_AND_ASSERT_MES(si < tx.vin.size(), void(), "Internal error: wrong tx transfer details: spend index=" << si << " is greater than transaction inputs vector " << tx.vin.size()); - if (tx.vin[si].type() == typeid(currency::txin_to_key)) - res_td.spn.push_back(boost::get(tx.vin[si]).amount); - } - - for (auto ri : td.receive_indices) - { - WLT_CHECK_AND_ASSERT_MES(ri < tx.vout.size(), void(), "Internal error: wrong tx transfer details: reciev index=" << ri << " is greater than transaction outputs vector " << tx.vout.size()); - VARIANT_SWITCH_BEGIN(tx.vout[ri]); - VARIANT_CASE_CONST(tx_out_bare, o) - if (o.target.type() == typeid(currency::txout_to_key)) - { - res_td.rcv.push_back(o.amount); - } - VARIANT_CASE_CONST(tx_out_zarcanum, o); - //@#@ - VARIANT_SWITCH_END(); - - } -} -//---------------------------------------------------------------------------------------------------- std::string wallet2::transfer_flags_to_str(uint32_t flags) { std::string result(5, ' '); @@ -466,7 +441,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t it->second.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; it->second.m_spent_height = height; WLT_LOG_L0("Spent multisig out: " << multisig_id << ", amount: " << print_money(currency::get_amount_from_variant(in)) << ", with tx: " << ptc.tx_hash() << ", at height " << height); - ptc.mtd.spent_indices.push_back(ptc.i); + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ ptc.i }); } } VARIANT_CASE_CONST(currency::txin_htlc, in_htlc) @@ -638,7 +613,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t continue; // skip the output } - ptc.mtd.receive_indices.push_back(o); + ptc.employed_entries.receive.push_back(wallet_public::employed_tx_entry{ o , out.amount , out.asset_id}); m_transfers.push_back(boost::value_initialized()); transfer_details& td = m_transfers.back(); @@ -1453,9 +1428,11 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces PROFILE_FUNC("wallet2::prepare_wti"); wti.tx = tx_process_context.tx; + load_wti_from_process_transaction_context(wti, tx_process_context); + wti.height = tx_process_context.height; - fill_transfer_details(tx_process_context.tx, tx_process_context.mtd, wti.td); - wti.unlock_time = get_max_unlock_time_from_receive_indices(tx_process_context.tx, tx_process_context.mtd); + wti.employed_entries = tx_process_context.employed_entries; + wti.unlock_time = get_max_unlock_time_from_receive_indices(tx_process_context.tx, tx_process_context.employed_entries); wti.timestamp = tx_process_context.timestamp; wti.tx_blob_size = static_cast(currency::get_object_blobsize(wti.tx)); wti.tx_hash = tx_process_context.tx_hash(); @@ -1463,7 +1440,7 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces bc_services::extract_market_instructions(wti.marketplace_entries, wti.tx.attachment); // escrow transactions, which are built with TX_FLAG_SIGNATURE_MODE_SEPARATE flag actually encrypt attachments - // with buyer as a sender, and seller as receiver, despite the fact that for both sides transaction seen as outgoing + // with buyer as a sender, and seller as receiver, despite the fact that for both sides transaction seen as outgoing. // so here to decrypt tx properly we need to figure out, if this transaction is actually escrow acceptance. //we check if spent_indices have zero then input do not belong to this account, which means that we are seller for this //escrow, and decryption should be processed as income flag @@ -1471,7 +1448,17 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces //let's assume that the one who pays for tx fee is sender of tx bool decrypt_attachment_as_income = !(tx_process_context.total_balance_change.count(currency::native_coin_asset_id) && tx_process_context.total_balance_change.at(currency::native_coin_asset_id) < 0 ); std::vector decrypted_att; - if (wti.tx_type == GUI_TX_TYPE_ESCROW_TRANSFER && std::find(tx_process_context.mtd.spent_indices.begin(), tx_process_context.mtd.spent_indices.end(), 0) == tx_process_context.mtd.spent_indices.end()) + bool has_zero_input_as_spent = false; + for (const auto& item : tx_process_context.employed_entries.spent) + { + if (item.index == 0) + { + has_zero_input_as_spent = true; + break; + } + } + + if (wti.tx_type == GUI_TX_TYPE_ESCROW_TRANSFER && !has_zero_input_as_spent) decrypt_attachment_as_income = true; @@ -1499,7 +1486,7 @@ void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti) this->balance(balances, mined_balance); m_wcallback->on_transfer2(wti, balances, mined_balance); // second call for legacy callback handlers - m_wcallback->on_transfer2(wti, balances, mined_balance); + //m_wcallback->on_transfer2(wti, balances, mined_balance); } //---------------------------------------------------------------------------------------------------- /* @@ -1535,7 +1522,7 @@ void wallet2::handle_money_received2(const currency::block& b, const currency::t } */ //---------------------------------------------------------------------------------------------------- -void wallet2::make_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context) +void wallet2::load_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context) { wti.remote_addresses = tx_process_context.recipients; wti.remote_aliases = tx_process_context.remote_aliases; @@ -1561,15 +1548,13 @@ void wallet2::make_wti_from_process_transaction_context(wallet_public::wallet_tr } wti.subtransfers.push_back(wsti); } - - prepare_wti(wti, tx_process_context); } //---------------------------------------------------------------------------------------------------- void wallet2::handle_money(const currency::block& b, const process_transaction_context& tx_process_context) { m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); - make_wti_from_process_transaction_context(wti, tx_process_context); + prepare_wti(wti, tx_process_context); WLT_LOG_L1("[MONEY SPENT]: " << epee::serialization::store_t_to_json(wti)); rise_on_transfer2(wti); } @@ -2127,6 +2112,162 @@ uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet( return tid; } //---------------------------------------------------------------------------------------------------- +void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) +{ + const transaction& tx = ptc.tx; + // read extra + std::vector outs; + //uint64_t sum_of_received_native_outs = 0; + crypto::public_key tx_pub_key = null_pkey; + bool 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, derivation); + THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); + + //collect incomes + for (auto& o : outs) + { + ptc.total_balance_change[o.asset_id] += o.amount; + ptc.employed_entries.receive.push_back(wallet_public::employed_tx_entry{ o.index, o.amount, o.asset_id }); + } + + + bool new_multisig_spend_detected = false; + //check if we have spendings + //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++) + { + auto& in = tx.vin[i]; + if (in.type() == typeid(currency::txin_to_key)) + { + const currency::txin_to_key& intk = 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(intk.amount, intk.key_offsets); + } + else + { + // wallet with spend secret key -- we can calculate own key images and then search among them + auto it = m_key_images.find(intk.k_image); + if (it != m_key_images.end()) + { + tid = it->second; + } + } + + if (tid != UINT64_MAX) + { + // own output is being spent by this input + //sum_of_spent_native_coin += intk.amount; + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers[tid].amount(), m_transfers[tid].get_asset_id() }); + spend_transfers.push_back(tid); + ptc.total_balance_change[currency::native_coin_asset_id] -= m_transfers[tid].amount(); + CHECK_AND_ASSERT_THROW_MES(m_transfers[tid].get_asset_id() == currency::native_coin_asset_id, "Unexpected asset id for native txin_to_key"); + } + } + 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) + { + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers[tid].amount(), m_transfers[tid].get_asset_id() }); + spend_transfers.push_back(tid); + ptc.total_balance_change[m_transfers[tid].get_asset_id()] -= m_transfers[tid].amount(); + } + } + else if (in.type() == typeid(currency::txin_multisig)) + { + crypto::hash multisig_id = boost::get(in).multisig_out_id; + auto it = m_multisig_transfers.find(multisig_id); + if (it != m_multisig_transfers.end()) + { + //ptc.employed_entries.spent_indices.push_back(i); + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i }); + if (ptc.pmultisig_entries) + { + r = ptc.pmultisig_entries->insert(std::make_pair(multisig_id, std::make_pair(tx, ptc.employed_entries))).second; + if (!r) + { + WLT_LOG_RED("Warning: Receiving the same multisig out id from tx pool more then once: " << multisig_id, LOG_LEVEL_0); + } + } + if (m_unconfirmed_multisig_transfers.count(multisig_id) == 0) + { + // new unconfirmed multisig (see also comments on multisig tranafers handling below) + uint32_t flags_before = it->second.m_flags; + it->second.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; // mark as spent + it->second.m_spent_height = 0; // height 0 means unconfirmed + WLT_LOG_L0("From tx pool got new unconfirmed multisig out with id: " << multisig_id << " tx: " << get_transaction_hash(tx) << " Marked as SPENT, flags: " << flags_before << " -> " << it->second.m_flags); + new_multisig_spend_detected = true; + } + + } + } + } + + //do final calculations + bool has_in_transfers = false; + bool has_out_transfers = false; + for (const auto& bce : ptc.total_balance_change) + { + if (bce.second > 0) + { + has_in_transfers = true; + } + else if (bce.second < 0) + { + has_out_transfers = true; + } + } + if (!is_tx_expired(tx, ptc.tx_expiration_ts_median) && (has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) + { + m_unconfirmed_in_transfers[ptc.tx_hash()] = tx; + if (m_unconfirmed_txs.count(ptc.tx_hash())) + return; + + //prepare notification about pending transaction + wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, ptc.tx_hash()); + prepare_wti(unconfirmed_wti, ptc); + for (auto tr_index : spend_transfers) + { + if (tr_index > m_transfers.size()) + { + WLT_LOG_ERROR("INTERNAL ERROR: tr_index " << tr_index << " more then m_transfers.size()=" << m_transfers.size()); + continue; + } + uint32_t flags_before = m_transfers[tr_index].m_flags; + m_transfers[tr_index].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; + WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers[tr_index].m_flags << ", reason: UNCONFIRMED tx: " << ptc.tx_hash()); + unconfirmed_wti.selected_indicies.push_back(tr_index); + } + rise_on_transfer2(unconfirmed_wti); + } +} + + void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) { //get transaction pool content @@ -2163,7 +2304,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) //- @#@ ----- debug std::unordered_map unconfirmed_in_transfers_local(std::move(m_unconfirmed_in_transfers)); - std::unordered_map> unconfirmed_multisig_transfers_from_tx_pool; + multisig_entries_map unconfirmed_multisig_transfers_from_tx_pool; has_related_alias_in_unconfirmed = false; uint64_t tx_expiration_ts_median = res.tx_expiration_ts_median; //get_tx_expiration_median(); @@ -2172,6 +2313,8 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) currency::transaction tx; //money_transfer2_details td; process_transaction_context ptc(tx); + ptc.tx_expiration_ts_median = tx_expiration_ts_median; + ptc.pmultisig_entries = &unconfirmed_multisig_transfers_from_tx_pool; bool r = parse_and_validate_tx_from_blob(tx_blob, tx); THROW_IF_TRUE_WALLET_EX(!r, error::tx_parse_error, tx_blob); has_related_alias_in_unconfirmed |= has_related_alias_entry_unconfirmed(tx); @@ -2184,152 +2327,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) continue; } - // read extra - std::vector outs; - //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, derivation); - THROW_IF_TRUE_WALLET_EX(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); - - //collect incomes - for (auto& o : outs) - { - ptc.total_balance_change[o.asset_id] += o.amount; - ptc.mtd.receive_indices.push_back(o.index); - } - - - bool new_multisig_spend_detected = false; - //check if we have spendings - //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++) - { - auto& in = tx.vin[i]; - if (in.type() == typeid(currency::txin_to_key)) - { - const currency::txin_to_key& intk = 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(intk.amount, intk.key_offsets); - } - else - { - // wallet with spend secret key -- we can calculate own key images and then search among them - auto it = m_key_images.find(intk.k_image); - if (it != m_key_images.end()) - { - tid = it->second; - } - } - - if (tid != UINT64_MAX) - { - // own output is being spent by this input - //sum_of_spent_native_coin += intk.amount; - ptc.mtd.spent_indices.push_back(i); - spend_transfers.push_back(tid); - ptc.total_balance_change[currency::native_coin_asset_id] -= m_transfers[tid].amount(); - CHECK_AND_ASSERT_THROW_MES(m_transfers[tid].get_asset_id() == currency::native_coin_asset_id, "Unexpected asset id for native txin_to_key"); - } - } - 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) - { - ptc.mtd.spent_indices.push_back(i); - spend_transfers.push_back(tid); - ptc.total_balance_change[m_transfers[tid].get_asset_id()] -= m_transfers[tid].amount(); - } - } - else if (in.type() == typeid(currency::txin_multisig)) - { - crypto::hash multisig_id = boost::get(in).multisig_out_id; - auto it = m_multisig_transfers.find(multisig_id); - if (it != m_multisig_transfers.end()) - { - ptc.mtd.spent_indices.push_back(i); - r = unconfirmed_multisig_transfers_from_tx_pool.insert(std::make_pair(multisig_id, std::make_pair(tx, ptc.mtd))).second; - if (!r) - { - WLT_LOG_RED("Warning: Receiving the same multisig out id from tx pool more then once: " << multisig_id, LOG_LEVEL_0); - } - if (m_unconfirmed_multisig_transfers.count(multisig_id) == 0) - { - // new unconfirmed multisig (see also comments on multisig tranafers handling below) - uint32_t flags_before = it->second.m_flags; - it->second.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; // mark as spent - it->second.m_spent_height = 0; // height 0 means unconfirmed - WLT_LOG_L0("From tx pool got new unconfirmed multisig out with id: " << multisig_id << " tx: " << get_transaction_hash(tx) << " Marked as SPENT, flags: " << flags_before << " -> " << it->second.m_flags); - new_multisig_spend_detected = true; - } - - } - } - } - - //do final calculations - bool has_in_transfers = false; - bool has_out_transfers = false; - for (const auto& bce : ptc.total_balance_change) - { - if (bce.second > 0) - { - has_in_transfers = true; - } - else if (bce.second < 0) - { - has_out_transfers = true; - } - } - if (!is_tx_expired(tx, tx_expiration_ts_median) && (has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) - { - m_unconfirmed_in_transfers[ptc.tx_hash()] = tx; - if (m_unconfirmed_txs.count(ptc.tx_hash())) - continue; - - //prepare notification about pending transaction - wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, ptc.tx_hash()); - make_wti_from_process_transaction_context(unconfirmed_wti, ptc); - for (auto tr_index : spend_transfers) - { - if (tr_index > m_transfers.size()) - { - WLT_LOG_ERROR("INTERNAL ERROR: tr_index " << tr_index << " more then m_transfers.size()=" << m_transfers.size()); - continue; - } - uint32_t flags_before = m_transfers[tr_index].m_flags; - m_transfers[tr_index].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; - WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers[tr_index].m_flags << ", reason: UNCONFIRMED tx: " << ptc.tx_hash()); - unconfirmed_wti.selected_indicies.push_back(tr_index); - } - rise_on_transfer2(unconfirmed_wti); - } + handle_unconfirmed_tx(ptc); } // Compare unconfirmed multisigs containers @@ -3275,13 +3273,23 @@ bool wallet2::balance(std::unordered_map& splitted_dsts) { PROFILE_FUNC("wallet2::add_sent_unconfirmed_tx"); - wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, currency::get_transaction_hash(tx)); - - unconfirmed_wti.tx = tx; - unconfirmed_wti.remote_addresses = recipients; + process_transaction_context ptc(tx); + ptc.recipients = recipients; for (auto addr : recipients) - unconfirmed_wti.remote_aliases.push_back(get_alias_for_address(addr)); - - process_transaction_context tx_process_context(tx); - -// for (const auto& sel_i : selected_indicies) -// { -// crypto::public_key asset_id = m_transfers[sel_i].get_asset_id(); -// if (asset_id == currency::native_coin_asset_id) -// { -// tx_process_context.spent_own_native_inputs = true; -// } -// tx_process_context.total_balance_change[asset_id] -= m_transfers[sel_i].amount(); -// } - - - for (auto& d : splitted_dsts) - { - if (d.addr.size() && - d.addr.back().spend_public_key == m_account.get_keys().account_address.spend_public_key && - d.addr.back().view_public_key == m_account.get_keys().account_address.view_public_key) - { - unconfirmed_wti.td.rcv.push_back(d.amount); - tx_process_context.total_balance_change[d.asset_id] += d.amount; - } - } + ptc.remote_aliases.push_back(get_alias_for_address(addr)); + handle_unconfirmed_tx(ptc); + wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, currency::get_transaction_hash(tx)); + //override some info that might be missing unconfirmed_wti.selected_indicies = selected_indicies; - - // check all inputs for spending (compare key images) - //scan key images - for (auto& i : tx.vin) - { - crypto::key_image ki{}; - if (get_key_image_from_txin_v(i, ki)) - { - if (m_key_images.count(ki)) - { - auto it = m_key_images.find(ki); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_key_images.end(), "[read_money_transfer2_details_from_tx]Unknown key image in tx: " << get_transaction_hash(tx)); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "[read_money_transfer2_details_from_tx]Index out of range for key image in tx: " << get_transaction_hash(tx)); - unconfirmed_wti.td.spn.push_back(m_transfers[it->second].amount()); - - - crypto::public_key asset_id = m_transfers[it->second].get_asset_id(); - if (asset_id == currency::native_coin_asset_id) - { - tx_process_context.spent_own_native_inputs = true; - } - tx_process_context.total_balance_change[asset_id] -= m_transfers[it->second].amount(); - } - } - } - - prepare_wti(unconfirmed_wti, tx_process_context); - rise_on_transfer2(unconfirmed_wti); } //---------------------------------------------------------------------------------------------------- std::string wallet2::get_alias_for_address(const std::string& addr) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c43286da..12689ca6 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -105,12 +105,6 @@ namespace tools #pragma pack (pop) - struct money_transfer2_details - { - std::vector receive_indices; - std::vector spent_indices; - }; - class i_wallet2_callback { @@ -556,13 +550,15 @@ namespace tools END_SERIALIZE() }; + typedef std::unordered_map> multisig_entries_map; + struct process_transaction_context { process_transaction_context(const currency::transaction& t) : tx(t) {} const currency::transaction& tx; bool spent_own_native_inputs = false; // check all outputs for spending (compare key images) - money_transfer2_details mtd; + wallet_public::employed_tx_entries employed_entries; bool is_pos_coinbase = false; bool coin_base_tx = false; //PoW block don't have change, so all outs supposed to be marked as "mined" @@ -574,6 +570,8 @@ namespace tools std::unordered_map total_balance_change; std::vector recipients; std::vector remote_aliases; + multisig_entries_map* pmultisig_entries = nullptr; + uint64_t tx_expiration_ts_median = 0; const crypto::hash& tx_hash() const { @@ -633,6 +631,7 @@ namespace tools void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; } bool has_related_alias_entry_unconfirmed(const currency::transaction& tx); + void handle_unconfirmed_tx(process_transaction_context& ptc); void scan_tx_pool(bool& has_related_alias_in_unconfirmed); void refresh(); void refresh(size_t & blocks_fetched); @@ -945,7 +944,7 @@ namespace tools void finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true ); std::string get_log_prefix() const { return m_log_prefix; } - static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td); + static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const wallet_public::employed_tx_entries& td); bool get_utxo_distribution(std::map& distribution); uint64_t get_sync_progress(); uint64_t get_wallet_file_size()const; @@ -1024,7 +1023,7 @@ private: void prepare_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att); void handle_money(const currency::block& b, const process_transaction_context& tx_process_context); - void make_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); + void load_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); @@ -1091,8 +1090,6 @@ private: const std::vector& decrypted_items, crypto::hash& ms_id, bc_services::contract_private_details& cpd, const currency::transaction& proposal_template_tx); - - void fill_transfer_details(const currency::transaction& tx, const tools::money_transfer2_details& td, tools::wallet_public::wallet_transfer_info_details& res_td) const; void print_source_entry(std::stringstream& output, const currency::tx_source_entry& src) const; @@ -1267,13 +1264,6 @@ namespace boost a & x.transfer_index; } - template - inline void serialize(Archive& a, tools::wallet_public::wallet_transfer_info_details& x, const boost::serialization::version_type ver) - { - a & x.rcv; - a & x.spn; - } - template inline void serialize(Archive& a, tools::wallet_public::escrow_contract_details_basic& x, const boost::serialization::version_type ver) { @@ -1363,7 +1353,7 @@ namespace tools "; flags: " << flags_before << " -> " << td.m_flags); } - ptc.mtd.spent_indices.push_back(ptc.i); + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ ptc.i, td.amount(), td.get_asset_id()}); remove_transfer_from_expiration_list(tr_index); } return true; diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 279fc41a..8c23e5a5 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -24,16 +24,39 @@ namespace wallet_public #define WALLET_RPC_STATUS_BUSY "BUSY" - struct wallet_transfer_info_details - { - std::list rcv; - std::list spn; + struct employed_tx_entry { + uint64_t index = 0; + uint64_t amount = 0; + crypto::public_key asset_id = currency::native_coin_asset_id; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(rcv) - KV_SERIALIZE(spn) + KV_SERIALIZE(index) + KV_SERIALIZE(amount) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) END_KV_SERIALIZE_MAP() + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(index) + BOOST_SERIALIZE(amount) + BOOST_SERIALIZE(asset_id) + END_BOOST_SERIALIZATION() + + }; + + struct employed_tx_entries + { + std::vector receive; + std::vector spent; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(receive) + KV_SERIALIZE(spent) + END_KV_SERIALIZE_MAP() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(receive) + BOOST_SERIALIZE(spent) + END_BOOST_SERIALIZATION() }; struct escrow_contract_details_basic @@ -122,7 +145,7 @@ namespace wallet_public bool is_mixing; bool is_mining; uint64_t tx_type; - wallet_transfer_info_details td; + employed_tx_entries employed_entries; std::vector service_entries; std::vector remote_addresses; //optional std::vector remote_aliases; //optional, describe only if there only one remote address @@ -149,7 +172,7 @@ namespace wallet_public KV_SERIALIZE_BLOB_AS_HEX_STRING(payment_id) KV_SERIALIZE(comment) KV_SERIALIZE(timestamp) - KV_SERIALIZE(td) + KV_SERIALIZE(employed_entries) KV_SERIALIZE(fee) KV_SERIALIZE(is_service) KV_SERIALIZE(is_mixing) @@ -171,7 +194,7 @@ namespace wallet_public BOOST_SERIALIZE(tx_blob_size) BOOST_SERIALIZE(payment_id) BOOST_SERIALIZE(remote_addresses) - BOOST_SERIALIZE(td) + BOOST_SERIALIZE(employed_entries) BOOST_SERIALIZE(tx) BOOST_SERIALIZE(remote_aliases) BOOST_SERIALIZE(comment) From 2860d030a3f79d5880b3f593fb3a73a141cdf764 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Fri, 16 Jun 2023 20:19:49 +0200 Subject: [PATCH 09/12] fixes of different situations related to contracts and unconfirmed state --- src/common/boost_serialization_maps.h | 11 +++++++++++ src/wallet/wallet2.cpp | 26 +++++++++++++++++++++----- src/wallet/wallet2.h | 22 +++++++++------------- tests/core_tests/chaingen.cpp | 20 +++++++++++++++++++- tests/core_tests/chaingen.h | 2 +- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/src/common/boost_serialization_maps.h b/src/common/boost_serialization_maps.h index bd8436d9..12a10d74 100644 --- a/src/common/boost_serialization_maps.h +++ b/src/common/boost_serialization_maps.h @@ -6,6 +6,17 @@ #define BEGIN_BOOST_SERIALIZATION() template inline void serialize(t_archive &_arch, const unsigned int ver) { +template struct TAssertEquality { + static_assert(A == B, "Serialization map is not updated, sizeof() missmatch"); + static constexpr bool _cResult = (A == B); +}; + +//experemental feature: self-validated serialization map, needed to not forget add new members to serialization maps +#define BEGIN_BOOST_SERIALIZATION_SV(sz) BEGIN_BOOST_SERIALIZATION() \ + static constexpr bool _cIsEqual = TAssertEquality::_cResult; + + + #define BOOST_SERIALIZE(x) _arch & x; #define END_BOOST_SERIALIZATION() } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 898cf5d8..bc45bf27 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -834,7 +834,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } - if (has_in_transfers || has_out_transfers) + if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation)) { ptc.timestamp = get_block_datetime(b); handle_money(b, ptc); @@ -1202,6 +1202,15 @@ void wallet2::change_contract_state(wallet_public::escrow_contract_details_basic contract.state = new_state; } //----------------------------------------------------------------------------------------------------- +void from_outs_to_received_items(const std::vector& outs, std::vector& received, const currency::transaction& tx) +{ + for (const auto& item : outs) + { + if(!out_is_multisig(tx.vout[item.index])) + received.push_back(tools::wallet2::payment_details_subtransfer{ item.asset_id, item.amount}); + } +} +//----------------------------------------------------------------------------------------------------- bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc_services::proposal_body& prop) { PROFILE_FUNC("wallet2::handle_proposal"); @@ -1237,8 +1246,9 @@ bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc std::vector outs; bool r = lookup_acc_outs(m_account.get_keys(), prop.tx_template, outs, derivation); THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to lookup_acc_outs for tx: " << get_transaction_hash(prop.tx_template)); - - add_transfers_to_expiration_list(found_transfers, ed.expiration_time, wti.tx_hash); + std::vector received; + from_outs_to_received_items(outs, received, prop.tx_template); + add_transfers_to_expiration_list(found_transfers, received, ed.expiration_time, wti.tx_hash); WLT_LOG_GREEN("Locked " << found_transfers.size() << " transfers due to proposal " << ms_id, LOG_LEVEL_0); } @@ -2129,6 +2139,9 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) //collect incomes for (auto& o : outs) { + if(out_is_multisig(tx.vout[o.index])) + continue; + ptc.total_balance_change[o.asset_id] += o.amount; ptc.employed_entries.receive.push_back(wallet_public::employed_tx_entry{ o.index, o.amount, o.asset_id }); } @@ -4876,7 +4889,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details& finalize_transaction(ftp, tx, one_time_key, false); } //---------------------------------------------------------------------------------------------------- -void wallet2::add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, const crypto::hash& related_tx_id) +void wallet2::add_transfers_to_expiration_list(const std::vector& selected_transfers, const std::vector& received, uint64_t expiration, const crypto::hash& related_tx_id) { // check all elements in selected_transfers for being already mentioned in m_money_expirations std::vector selected_transfers_local; @@ -4899,6 +4912,7 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele m_money_expirations.back().expiration_time = expiration; m_money_expirations.back().selected_transfers = selected_transfers_local; m_money_expirations.back().related_tx_id = related_tx_id; + m_money_expirations.back().receved = received; std::stringstream ss; for (auto tr_ind : m_money_expirations.back().selected_transfers) @@ -5158,6 +5172,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal ctp.dsts[i].asset_id = proposal_detais.to_bob[i].asset_id; } // Here is an expected in return funds + std::vector for_expiration_list; for (size_t j = 0; j != proposal_detais.to_alice.size(); j++, i++) { ctp.dsts[i].amount = proposal_detais.to_alice[j].amount; @@ -5165,6 +5180,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide; ctp.dsts[i].addr.push_back(m_account.get_public_address()); ctp.dsts[i].asset_id = proposal_detais.to_alice[j].asset_id; + for_expiration_list.push_back(payment_details_subtransfer{ ctp.dsts[i].asset_id, ctp.dsts[i].amount}); } currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); @@ -5175,7 +5191,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal selected_transfers = ftp.selected_transfers; currency::finalized_tx finalize_result = AUTO_VAL_INIT(finalize_result); finalize_transaction(ftp, finalize_result, false); - add_transfers_to_expiration_list(selected_transfers, proposal_detais.expiration_time, currency::null_hash); + add_transfers_to_expiration_list(selected_transfers, for_expiration_list, proposal_detais.expiration_time, currency::null_hash); //wrap it all proposal.tx_template = finalize_result.tx; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 12689ca6..7d06135e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -488,6 +488,14 @@ namespace tools std::vector selected_transfers; uint64_t expiration_time = 0; crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) + std::vector receved; + + BEGIN_BOOST_SERIALIZATION_SV(104) + BOOST_SERIALIZE(selected_transfers) + BOOST_SERIALIZE(expiration_time) + BOOST_SERIALIZE(related_tx_id) + BOOST_SERIALIZE(receved) + END_BOOST_SERIALIZATION() }; /* @@ -993,7 +1001,7 @@ private: // -------- t_transport_state_notifier ------------------------------------------------ virtual void notify_state_change(const std::string& state_code, const std::string& details = std::string()); // ------------------------------------------------------------------------------------ - void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, const crypto::hash& related_tx_id); + void add_transfers_to_expiration_list(const std::vector& selected_transfers, const std::vector& received, uint64_t expiration, const crypto::hash& related_tx_id); void remove_transfer_from_expiration_list(uint64_t transfer_index); void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature, keys_file_data& kf_data); void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector* pglobal_indexes); @@ -1288,18 +1296,6 @@ namespace boost a & x.contract_id; } - - template - inline void serialize(Archive& a, tools::wallet2::expiration_entry_info& x, const boost::serialization::version_type ver) - { - a & x.expiration_time; - a & x.selected_transfers; - a & x.related_tx_id; - } - - - - } } diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 1990ead4..d27f4af2 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -2067,7 +2067,7 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, return true; } -bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result) +bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result /* = true */) { std::deque transfers; w.get_transfers(transfers); @@ -2078,6 +2078,24 @@ bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_ if (td.m_flags == (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION)) result += td.amount(); } + if (substruct_change_from_result) + { + const std::list& ee = w.get_expiration_entries(); + for (auto &e : ee) + { + uint64_t change_amount_native = 0; + for (const auto rd : e.receved) + { + if (rd.asset_id == currency::native_coin_asset_id) + change_amount_native += rd.amount; + } + + CHECK_AND_ASSERT_MES(result >= change_amount_native, false, "wrong transfers: result: " << print_money(result) << " is expected to be NOT LESS than change_amount: " << print_money(change_amount_native)); + result -= change_amount_native; + } + } + + return true; } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 6ab7b76b..ba47f464 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -724,7 +724,7 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, const std::vector& attachments = empty_attachment, const std::vector& extra = empty_extra); -bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result); +bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result = true); bool check_wallet_balance_blocked_for_escrow(const tools::wallet2& w, const char* wallet_name, uint64_t expected_amount); bool refresh_wallet_and_check_balance(const char* intro_log_message, const char* wallet_name, std::shared_ptr wallet, uint64_t expected_total, bool print_transfers = false, From 71cc21845a9c0b1bb3ed2bb5f69e225823e0cc2c Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Mon, 19 Jun 2023 00:19:25 +0200 Subject: [PATCH 10/12] escrow_custom_test fixed(with many many tiny fixes) --- src/wallet/wallet2.cpp | 25 ++++++++++++++++++++---- tests/core_tests/escrow_wallet_tests.cpp | 3 ++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index bc45bf27..f1a09319 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1273,8 +1273,19 @@ bool wallet2::handle_release_contract(wallet_public::wallet_transfer_info& wti, else if (release_instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN) { change_contract_state(it->second, wallet_public::escrow_contract_details_basic::contract_released_burned, ms_id, wti); - WLT_CHECK_AND_ASSERT_MES(wti.subtransfers.size(), false, "Unexpected subtransfers size"); //TODO: subject for refactoring - wti.subtransfers.back().amount = it->second.private_detailes.amount_to_pay + it->second.private_detailes.amount_a_pledge + it->second.private_detailes.amount_b_pledge; + wallet_public::wallet_sub_transfer_info* subptr = nullptr; + for (auto& s: wti.subtransfers) + { + if (s.asset_id == currency::native_coin_asset_id) + subptr = &s; + } + if (subptr == nullptr) + { + wti.subtransfers.push_back(wallet_public::wallet_sub_transfer_info()); + subptr = &wti.subtransfers.back(); + } + + subptr->amount = it->second.private_detailes.amount_to_pay + it->second.private_detailes.amount_a_pledge + it->second.private_detailes.amount_b_pledge; if (!it->second.is_a) { wti.fee = currency::get_tx_fee(wti.tx); @@ -2255,7 +2266,7 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) has_out_transfers = true; } } - if (!is_tx_expired(tx, ptc.tx_expiration_ts_median) && (has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) + if (!is_tx_expired(tx, ptc.tx_expiration_ts_median) && (new_multisig_spend_detected || has_in_transfers || has_out_transfers || (currency::is_derivation_used_to_encrypt(tx, derivation)))) { m_unconfirmed_in_transfers[ptc.tx_hash()] = tx; if (m_unconfirmed_txs.count(ptc.tx_hash())) @@ -3289,7 +3300,13 @@ bool wallet2::balance(std::unordered_map& events) const test_details.push_back(cd); } + for(auto cd : test_details) { DO_CALLBACK_PARAMS_STR(events, "check", epee::serialization::store_t_to_json(cd)); @@ -1637,7 +1638,7 @@ bool escrow_custom_test::generate(std::vector& events) const prev_block = blk_n; } - + return true; } From a744092d9ab7753ca843096a40b1245fdba4eb4e Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Tue, 20 Jun 2023 21:59:02 +0200 Subject: [PATCH 11/12] last fixes over bunch of tests --- src/wallet/wallet2.cpp | 6 ++++-- src/wallet/wallet2.h | 2 +- tests/core_tests/wallet_tests.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f1a09319..3daccfb9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -834,7 +834,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } - if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation)) + if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation) || ptc.employed_entries.spent.size()) { ptc.timestamp = get_block_datetime(b); handle_money(b, ptc); @@ -898,7 +898,8 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i account_public_address sender_address = AUTO_VAL_INIT(sender_address); wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ }); if (wti.show_sender) - wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); + if(!wti.remote_addresses.size()) + wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); } else { @@ -2136,6 +2137,7 @@ uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet( void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) { const transaction& tx = ptc.tx; + ptc.timestamp = m_core_runtime_config.get_core_time(); // read extra std::vector outs; //uint64_t sum_of_received_native_outs = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 7d06135e..13ecdb1b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -490,7 +490,7 @@ namespace tools crypto::hash related_tx_id = currency::null_hash; // tx id which caused money lock, if any (ex: escrow proposal transport tx) std::vector receved; - BEGIN_BOOST_SERIALIZATION_SV(104) + BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(selected_transfers) BOOST_SERIALIZE(expiration_time) BOOST_SERIALIZE(related_tx_id) diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index b4540fcf..06f6931d 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1833,7 +1833,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ std::shared_ptr l(new wlt_lambda_on_transfer2_wrapper( [biggest_alias_reward](const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) -> bool { return std::count(wti.remote_aliases.begin(), wti.remote_aliases.end(), "minerminer") == 1 && - wti.get_native_amount() == biggest_alias_reward; + wti.get_native_amount() == biggest_alias_reward + get_tx_fee(wti.tx); } )); alice_wlt->callback(l); From c3397a00eb88fca70f18fc11281cfe45e8fa89ef Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Wed, 21 Jun 2023 22:45:31 +0200 Subject: [PATCH 12/12] fixes in simplewallet and mainwindow for new recent_history structure --- src/currency_core/currency_format_utils.h | 4 +- src/gui/qt-daemon/application/mainwindow.cpp | 8 +- src/gui/qt-daemon/layout | 2 +- src/simplewallet/simplewallet.cpp | 96 +++++++++++++++++--- src/simplewallet/simplewallet.h | 2 + src/wallet/wallet2.cpp | 32 +++++++ src/wallet/wallet2.h | 4 +- src/wallet/wallet_public_structs_defs.h | 2 + src/wallet/wallet_rpc_server.cpp | 1 + 9 files changed, 129 insertions(+), 22 deletions(-) diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 4cc15c8f..cef2f29a 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -577,9 +577,9 @@ namespace currency } //--------------------------------------------------------------- template - std::string print_money(t_number amount) + std::string print_money(t_number amount, uint64_t decimals = CURRENCY_DISPLAY_DECIMAL_POINT) { - return print_fixed_decimal_point(amount, CURRENCY_DISPLAY_DECIMAL_POINT); + return print_fixed_decimal_point(amount, decimals); } //--------------------------------------------------------------- diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index b61b4cce..51954544 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -1059,9 +1059,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) if (!m_tray_icon) return true; - if (!tei.ti.is_income) + if (tei.ti.has_outgoing_entries()) return true; - if (!tei.ti.amount) + if (!tei.ti.get_native_amount()) return true; // if (tei.ti.is_mining && m_wallet_states->operator [](tei.wallet_id) != view::wallet_status_info::wallet_state_ready) // return true; @@ -1075,9 +1075,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) return true; } - auto amount_str = currency::print_money_brief(tei.ti.amount); + auto amount_str = currency::print_money_brief(tei.ti.get_native_amount()); //@#@ add handling of assets std::string title, msg; - if (tei.ti.height == 0) // unconfirmed trx + if (tei.ti.height == 0) // unconfirmed tx { msg = amount_str + " " + CURRENCY_NAME_ABR + " " + m_localization[localization_id_is_received]; title = m_localization[localization_id_income_transfer_unconfirmed]; diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 1471e71f..e1aea269 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 1471e71f4ff685dd080e6551773cf129f1d02c43 +Subproject commit e1aea269ee057ccb5b68bce83b8beeb4866e560d diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 3e52378a..4b718e64 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -715,7 +715,7 @@ void simple_wallet::on_new_block(uint64_t height, const currency::block& block) m_refresh_progress_reporter.update(height, false); } //---------------------------------------------------------------------------------------------------- -std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount) +std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT) { std::string s = print_money(amount); size_t p = s.find_last_not_of('0'); @@ -729,13 +729,64 @@ std::string print_money_trailing_zeros_replaced_with_spaces(uint64_t amount) return s; } //---------------------------------------------------------------------------------------------------- +std::string simple_wallet::get_tocken_info_string(const crypto::public_key& asset_id, uint64_t& decimal_points) +{ + std::string token_info = "ZANO"; + decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT; + if (asset_id != currency::native_coin_asset_id) + { + currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb); + bool whitelisted = false; + if (!m_wallet->get_asset_id_info(asset_id, adb, whitelisted)) + { + token_info = "!UNKNOWN!"; + } + else { + decimal_points = adb.decimal_point; + token_info = adb.ticker; + + if (whitelisted) + { + token_info += "[*]"; + } + else + { + token_info += std::string("[") + epee::string_tools::pod_to_hex(asset_id) + "]"; + } + } + } + return token_info; +} +//---------------------------------------------------------------------------------------------------- void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { - epee::log_space::console_colors color = wti.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; - message_writer(color, false) << - "height " << wti.height << - ", tx " << wti.tx_hash << - " " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.amount) << (wti.is_income ? " received," : " spent"); + + if (wti.subtransfers.size() == 1) + { + epee::log_space::console_colors color = !wti.has_outgoing_entries() ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; + uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT; + std::string token_info = get_tocken_info_string(wti.subtransfers[0].asset_id, decimal_points); + message_writer(color, false) << + "height " << wti.height << + ", tx " << wti.tx_hash << + " " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.subtransfers[0].amount, decimal_points) << (wti.subtransfers[0].is_income ? " received," : " spent") << " " << token_info; + } + else + { + message_writer(epee::log_space::console_color_cyan, false) << + "height " << wti.height << + ", tx " << wti.tx_hash; + for (const auto& st : wti.subtransfers) + { + epee::log_space::console_colors color = st.is_income ? epee::log_space::console_color_green : epee::log_space::console_color_magenta; + uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT; + std::string token_info = get_tocken_info_string(st.asset_id, decimal_points); + + message_writer(epee::log_space::console_color_cyan, false) << " " + << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << (st.is_income ? " received," : " spent") << " " << token_info; + } + } + m_refresh_progress_reporter.update(wti.height, true); } //---------------------------------------------------------------------------------------------------- @@ -861,10 +912,10 @@ bool simple_wallet::show_balance(const std::vector& args/* = std::v return true; } //---------------------------------------------------------------------------------------------------- -bool print_wti(const tools::wallet_public::wallet_transfer_info& wti) +bool simple_wallet::print_wti(const tools::wallet_public::wallet_transfer_info& wti) { epee::log_space::console_colors cl; - if (wti.is_income) + if (!wti.has_outgoing_entries()) cl = epee::log_space::console_color_green; else cl = epee::log_space::console_color_magenta; @@ -886,11 +937,30 @@ bool print_wti(const tools::wallet_public::wallet_transfer_info& wti) remote_side += remote_side.empty() ? it : (separator + it); } - success_msg_writer(cl) << "[" << wti.transfer_internal_index << "]" << epee::misc_utils::get_time_str_v2(wti.timestamp) << " " - << (wti.is_income ? "Received " : "Sent ") - << print_money(wti.amount) << "(fee:" << print_money(wti.fee) << ") " - << remote_side - << " " << wti.tx_hash << payment_id_placeholder; + if (wti.subtransfers.size() == 1) + { + success_msg_writer(cl) << "[" << wti.transfer_internal_index << "]" << epee::misc_utils::get_time_str_v2(wti.timestamp) << " " + << (wti.subtransfers[0].is_income ? "Received " : "Sent ") + << print_money(wti.subtransfers[0].amount) << "(fee:" << print_money(wti.fee) << ") " + << remote_side + << " " << wti.tx_hash << payment_id_placeholder; + }else + { + success_msg_writer(cl) << "[" << wti.transfer_internal_index << "]" << epee::misc_utils::get_time_str_v2(wti.timestamp) << " (fee:" << print_money(wti.fee) << ") " + << remote_side + << " " << wti.tx_hash << payment_id_placeholder; + for (auto& st: wti.subtransfers) + { + epee::log_space::console_colors cl = st.is_income ? epee::log_space::console_color_green: epee::log_space::console_color_magenta; + uint64_t decimal_points = CURRENCY_DISPLAY_DECIMAL_POINT; + std::string token_info = get_tocken_info_string(st.asset_id, decimal_points); + + success_msg_writer(cl) + << (st.is_income ? "Received " : "Sent ") + << print_money(st.amount, decimal_points) << token_info; + } + + } return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 01d637e4..1073db08 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -104,6 +104,8 @@ namespace currency uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(); + std::string get_tocken_info_string(const crypto::public_key& asset_id, uint64_t& decimal_point); + bool simple_wallet::print_wti(const tools::wallet_public::wallet_transfer_info& wti); //----------------- i_wallet2_callback --------------------- virtual void on_new_block(uint64_t height, const currency::block& block) override; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 0b9de69c..12f90d4d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3405,6 +3405,38 @@ bool wallet2::balance(std::list& balances, u return true; } //---------------------------------------------------------------------------------------------------- +bool wallet2::get_asset_id_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, bool& whitelist_) const +{ + if (asset_id == currency::native_coin_asset_id) + { + return CURRENCY_NAME_ABR; + } + //check if asset is whitelisted or customly added + whitelist_ = false; + auto it_white = m_whitelisted_assets.find(asset_id); + if (it_white == m_whitelisted_assets.end()) + { + //check if it custom asset + auto it_cust = m_custom_assets.find(asset_id); + if (it_cust == m_custom_assets.end()) + { + return false; + } + else + { + asset_info = it_cust->second; + } + } + else + { + asset_info = it_white->second; + whitelist_ = true; + } + + return true; +} +//---------------------------------------------------------------------------------------------------- + uint64_t wallet2::balance() const { uint64_t stub = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 33f492fa..020b824d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -668,7 +668,7 @@ namespace tools uint64_t balance(uint64_t& unloked) const; uint64_t unlocked_balance() const; - + bool get_asset_id_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, bool& whitelist_) const; void transfer(uint64_t amount, const currency::account_public_address& acc, const crypto::public_key& asset_id = currency::native_coin_asset_id); void transfer(uint64_t amount, size_t fake_outs_count, const currency::account_public_address& acc, uint64_t fee = TX_DEFAULT_FEE, const crypto::public_key& asset_id = currency::native_coin_asset_id); void transfer(uint64_t amount, const currency::account_public_address& acc, currency::transaction& result_tx, const crypto::public_key& asset_id = currency::native_coin_asset_id); @@ -1195,7 +1195,7 @@ private: mutable uint64_t m_current_wallet_file_size; bool m_use_deffered_global_outputs; bool m_disable_tor_relay; - bool m_use_assets_whitelisting = false; + bool m_use_assets_whitelisting = true; mutable current_operation_context m_current_context; //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 8c23e5a5..ea84d484 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -561,9 +561,11 @@ namespace wallet_public { uint64_t amount; std::string address; + crypto::public_key asset_id; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) KV_SERIALIZE(address) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 87f90a0c..4219d50d 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -366,6 +366,7 @@ namespace tools payment_id = embedded_payment_id; } de.amount = it->amount; + de.asset_id = (it->asset_id == currency::null_pkey ? currency::native_coin_asset_id : it->asset_id); dsts.push_back(de); }