From 84fd02ea1db86399df062947f1a18186ff6e4160 Mon Sep 17 00:00:00 2001 From: selsta Date: Fri, 2 Oct 2026 20:51:59 +0200 Subject: [PATCH] wallet2: update multisig info for detached outputs (cherry picked from commit 48053f75dfed66cbb70aae21a17c5aa00cf3dc88) --- src/wallet/wallet2.cpp | 35 ++++++++++++++++++++++------------- src/wallet/wallet2.h | 2 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 75f5e9898..8e7144092 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2608,7 +2608,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { THROW_WALLET_EXCEPTION_IF(m_multisig_rescan_k.empty() && !m_multisig_rescan_info.empty(), error::wallet_internal_error, "NULL m_multisig_rescan_k"); - if (!m_multisig_rescan_info.empty() && m_multisig_rescan_info.front().size() >= m_transfers.size()) + if (m_multisig_rescan_info.size() >= m_transfers.size()) update_multisig_rescan_info(m_multisig_rescan_k, m_multisig_rescan_info, m_transfers.size() - 1); } LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); @@ -2690,7 +2690,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { THROW_WALLET_EXCEPTION_IF(m_multisig_rescan_k.empty() && !m_multisig_rescan_info.empty(), error::wallet_internal_error, "NULL m_multisig_rescan_k"); - if (!m_multisig_rescan_info.empty() && m_multisig_rescan_info.front().size() >= m_transfers.size()) + if (m_multisig_rescan_info.size() >= m_transfers.size()) update_multisig_rescan_info(m_multisig_rescan_k, m_multisig_rescan_info, m_transfers.size() - 1); } THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys"); @@ -15669,15 +15669,11 @@ void wallet2::update_multisig_rescan_info(const std::vector= m_transfers.size(), "Mismatched sizes of multisig_k and info"); + CHECK_AND_ASSERT_THROW_MES(n < info.size(), "Bad multisig info size"); MDEBUG("update_multisig_rescan_info: updating index " << n); transfer_details &td = m_transfers[n]; - td.m_multisig_info.clear(); - for (const auto &pi: info) - { - CHECK_AND_ASSERT_THROW_MES(n < pi.size(), "Bad pi size"); - td.m_multisig_info.push_back(pi[n]); - } + td.m_multisig_info = info[n]; m_key_images.erase(td.m_key_image); td.m_key_image = get_multisig_composite_key_image(n); td.m_key_image_known = true; @@ -15769,12 +15765,14 @@ size_t wallet2::import_multisig(std::vector blobs, bool re std::vector> k; auto wiper = epee::misc_utils::create_scope_leave_handler([&](){for (auto &v: k) memwipe(v.data(), v.size() * sizeof(v[0]));}); - k.reserve(m_transfers.size()); + k.reserve(std::max(m_transfers.size(), m_multisig_rescan_k.size())); for (const auto &td: m_transfers) k.push_back(td.m_multisig_k); + for (size_t n = m_transfers.size(); n < m_multisig_rescan_k.size(); ++n) + k.push_back(m_multisig_rescan_k[n]); // how many outputs we're going to update - size_t n_outputs = m_transfers.size(); + size_t n_outputs = k.size(); for (const auto &pi: info) if (pi.size() < n_outputs) n_outputs = pi.size(); @@ -15801,14 +15799,25 @@ size_t wallet2::import_multisig(std::vector blobs, bool re std::sort(info.begin(), info.end(), [](const std::vector &i0, const std::vector &i1){ return memcmp(&i0[0].m_signer, &i1[0].m_signer, sizeof(i0[0].m_signer)) < 0; }); } - // wipe prior pending rescan state and install its replacement only after full validation + auto rescan_info = m_multisig_rescan_info; + rescan_info.resize(std::max(rescan_info.size(), n_outputs)); + for (size_t n = 0; n < n_outputs; ++n) + { + auto &output_info = rescan_info[n]; + output_info.clear(); + output_info.reserve(info.size()); + for (auto &pi: info) + output_info.push_back(std::move(pi[n])); + } + + // Install the updated rescan state after validation. for (auto &v: m_multisig_rescan_k) memwipe(v.data(), v.size() * sizeof(v[0])); - m_multisig_rescan_info = std::move(info); + m_multisig_rescan_info = std::move(rescan_info); m_multisig_rescan_k = std::move(k); // first pass to determine where to detach the blockchain - for (size_t n = 0; n < n_outputs; ++n) + for (size_t n = 0; n < n_outputs && n < m_transfers.size(); ++n) { const transfer_details &td = m_transfers[n]; if (!td.m_key_image_partial) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index a3c792b87..0aeee2040 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -2003,7 +2003,7 @@ private: std::vector m_address_book; std::pair, std::vector> m_account_tags; uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value - std::vector> m_multisig_rescan_info; + std::vector> m_multisig_rescan_info; // output, then signer std::vector> m_multisig_rescan_k; serializable_unordered_map m_cold_key_images;