diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 446448972..9e4a6acab 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14626,9 +14626,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) { @@ -14688,18 +14691,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; + const epee::scope_guard wiper([&]() { 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(); @@ -14707,7 +14712,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"); @@ -14716,15 +14721,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) {