diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ff2a86420..e4697c2d1 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15419,9 +15419,12 @@ size_t wallet2::import_multisig(std::vector blobs, bool re { CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - if (!m_multisig_rescan_k.empty() && !m_multisig_rescan_info.empty()) + // consume pending rescan state from a prior import if refreshing + if (refresh_after_import && !m_multisig_rescan_k.empty() && !m_multisig_rescan_info.empty()) refresh(false); + // parse and validate locally so failures preserve any pending rescan state + std::vector> info; std::unordered_set seen; for (cryptonote::blobdata &data: blobs) { @@ -15487,18 +15490,20 @@ size_t wallet2::import_multisig(std::vector blobs, bool re } MINFO(boost::format("%u outputs found") % boost::lexical_cast(i.size())); - m_multisig_rescan_info.push_back(std::move(i)); + info.push_back(std::move(i)); } - CHECK_AND_ASSERT_THROW_MES(m_multisig_rescan_info.size() + 1 <= m_multisig_signers.size() && m_multisig_rescan_info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources"); + CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources"); - m_multisig_rescan_k.reserve(m_transfers.size()); + 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()); for (const auto &td: m_transfers) - m_multisig_rescan_k.push_back(td.m_multisig_k); + k.push_back(td.m_multisig_k); // how many outputs we're going to update size_t n_outputs = m_transfers.size(); - for (const auto &pi: m_multisig_rescan_info) + for (const auto &pi: info) if (pi.size() < n_outputs) n_outputs = pi.size(); @@ -15506,7 +15511,7 @@ size_t wallet2::import_multisig(std::vector blobs, bool re return 0; // check signers are consistent - for (const auto &pi: m_multisig_rescan_info) + for (const auto &pi: info) { CHECK_AND_ASSERT_THROW_MES(std::find(m_multisig_signers.begin(), m_multisig_signers.end(), pi[0].m_signer) != m_multisig_signers.end(), "Signer is not a member of this multisig wallet"); @@ -15515,15 +15520,21 @@ size_t wallet2::import_multisig(std::vector blobs, bool re } // trim data we don't have info for from all participants - for (auto &pi: m_multisig_rescan_info) + for (auto &pi: info) pi.resize(n_outputs); // sort by signer - if (!m_multisig_rescan_info.empty() && !m_multisig_rescan_info.front().empty()) + if (!info.empty() && !info.front().empty()) { - std::sort(m_multisig_rescan_info.begin(), m_multisig_rescan_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; }); + 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 + 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_k = std::move(k); + // first pass to determine where to detach the blockchain for (size_t n = 0; n < n_outputs; ++n) {