diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 36bbe317d67..6a50785e3d7 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1047,6 +1047,53 @@ crypto::chacha_key derive_cache_key(const crypto::chacha_key& keys_data_key, con return cache_key; } + +void recover_dests( + std::unordered_map &m_unconfirmed_txs, + std::unordered_map &m_confirmed_txs, + std::unordered_map &m_recoverable_dests) +{ + if (m_recoverable_dests.empty()) + return; + + for (auto it = m_recoverable_dests.begin(); it != m_recoverable_dests.end();) + { + auto confirmed_it = m_confirmed_txs.find(it->first); + if (confirmed_it != m_confirmed_txs.end()) + { + confirmed_it->second.m_dests = std::move(it->second.m_dests); + confirmed_it->second.m_payment_id = it->second.m_payment_id; + it = m_recoverable_dests.erase(it); + continue; + } + + auto unconfirmed_it = m_unconfirmed_txs.find(it->first); + if (unconfirmed_it != m_unconfirmed_txs.end()) + { + unconfirmed_it->second.m_dests = std::move(it->second.m_dests); + unconfirmed_it->second.m_payment_id = it->second.m_payment_id; + it = m_recoverable_dests.erase(it); + continue; + } + + ++it; + } +} + +std::unordered_map save_recoverable_dests( + const std::unordered_map &m_unconfirmed_txs, + const std::unordered_map &m_confirmed_txs) +{ + std::unordered_map recoverable_dests; + + for (const auto &unconfirmed_tx : m_unconfirmed_txs) + recoverable_dests[unconfirmed_tx.first] = wallet2_basic::destination_details{ .m_dests = unconfirmed_tx.second.m_dests, .m_payment_id = unconfirmed_tx.second.m_payment_id }; + for (const auto &confirmed_tx : m_confirmed_txs) + recoverable_dests[confirmed_tx.first] = wallet2_basic::destination_details{ .m_dests = confirmed_tx.second.m_dests, .m_payment_id = confirmed_tx.second.m_payment_id }; + + return recoverable_dests; +} + //----------------------------------------------------------------- } //namespace @@ -4567,6 +4614,9 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo m_multisig_rescan_k = std::vector>{}; LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", current sync height: " << m_blockchain.size() << ", balance (all accounts): " << print_money(balance_all(false)) << ", unlocked: " << print_money(unlocked_balance_all(false))); + + // Recover dests if there are any to recover + recover_dests(m_unconfirmed_txs, m_confirmed_txs, m_recoverable_dests); } //---------------------------------------------------------------------------------------------------- bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& received_money, bool& ok) @@ -6823,8 +6873,12 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass if (m_tree_cache.n_synced_blocks() == 0 && !m_transfers.empty() && m_has_ever_refreshed_from_node) { - // clear the wallet so that we re-sync the tree and get received output paths - // TODO: may want to warn users that this is happening before doing it, esp. because it'll delete tx dests + // We must be upgrading a pre-FCMP++ wallet to a FCMP++ wallet. + // Unfortunately, we have to clear the wallet and re-sync from the wallet's restore height, in order to sync the + // FCMP++ tree and get received output paths. + // But first, we save destination details, so that we don't lose them. We recover any recoverable dests after + // refreshing (recovery happens via recover_dests). + m_recoverable_dests = save_recoverable_dests(m_unconfirmed_txs, m_confirmed_txs); this->clear_soft(true); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index dc583b13c05..a04f51e8286 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -959,6 +959,7 @@ namespace tools if (version < 3) return true; FIELD(m_tree_cache) + FIELD(m_recoverable_dests) END_SERIALIZE() /*! @@ -1576,6 +1577,9 @@ namespace tools std::vector> m_multisig_rescan_k; std::unordered_map m_cold_key_images; + // This struct is used to make sure wallets upgrading from pre-FCMP++ to FCMP++ maintain saved destination details + std::unordered_map m_recoverable_dests; + uint64_t m_sync_blocks_time_ms; uint64_t m_outs_by_last_locked_time_ms; diff --git a/src/wallet/wallet2_basic/wallet2_boost_serialization.h b/src/wallet/wallet2_basic/wallet2_boost_serialization.h index 10b385a5983..e5b3ca80222 100644 --- a/src/wallet/wallet2_basic/wallet2_boost_serialization.h +++ b/src/wallet/wallet2_basic/wallet2_boost_serialization.h @@ -312,6 +312,13 @@ void serialize(Archive &a, wallet2_basic::confirmed_transfer_details &x, const u a & x.m_rings; } +template +void serialize(Archive &a, wallet2_basic::destination_details &x, const unsigned int ver) +{ + a & x.m_dests; + a & x.m_payment_id; +} + template void serialize(Archive& a, wallet2_basic::payment_details& x, const unsigned int ver) { @@ -423,6 +430,7 @@ BOOST_CLASS_VERSION(wallet2_basic::multisig_info::LR, 0) BOOST_CLASS_VERSION(wallet2_basic::multisig_info, 1) BOOST_CLASS_VERSION(wallet2_basic::unconfirmed_transfer_details, 8) BOOST_CLASS_VERSION(wallet2_basic::confirmed_transfer_details, 6) +BOOST_CLASS_VERSION(wallet2_basic::destination_details, 0) BOOST_CLASS_VERSION(wallet2_basic::payment_details, 5) BOOST_CLASS_VERSION(wallet2_basic::pool_payment_details, 1) BOOST_CLASS_VERSION(wallet2_basic::address_book_row, 18) diff --git a/src/wallet/wallet2_basic/wallet2_cocobo_serialization.h b/src/wallet/wallet2_basic/wallet2_cocobo_serialization.h index fa29851e7e5..487251e6687 100644 --- a/src/wallet/wallet2_basic/wallet2_cocobo_serialization.h +++ b/src/wallet/wallet2_basic/wallet2_cocobo_serialization.h @@ -114,6 +114,12 @@ BEGIN_SERIALIZE_OBJECT_FN(confirmed_transfer_details) FIELD_F(m_rings) END_SERIALIZE() +BEGIN_SERIALIZE_OBJECT_FN(destination_details) + VERSION_FIELD(0) + FIELD_F(m_dests) + FIELD_F(m_payment_id) +END_SERIALIZE() + BEGIN_SERIALIZE_OBJECT_FN(payment_details) VERSION_FIELD(0) FIELD_F(m_tx_hash) diff --git a/src/wallet/wallet2_basic/wallet2_types.h b/src/wallet/wallet2_basic/wallet2_types.h index f2dcf687b54..3283f494e4e 100644 --- a/src/wallet/wallet2_basic/wallet2_types.h +++ b/src/wallet/wallet2_basic/wallet2_types.h @@ -234,6 +234,12 @@ struct confirmed_transfer_details {} }; +struct destination_details +{ + std::vector m_dests; + crypto::hash m_payment_id{crypto::null_hash}; +}; + typedef std::vector amounts_container; struct payment_details {