diff options
author | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2022-08-16 20:20:38 +0000 |
---|---|---|
committer | moneromooo-monero <moneromooo-monero@users.noreply.github.com> | 2022-08-18 06:53:41 +0000 |
commit | c5579ac236962ac71cf39bd1928690fe7e1d1899 (patch) | |
tree | 00ab5fccb7d27531d611525e373d182ac09f5d9f /src/wallet/wallet2.cpp | |
parent | wallet2: fixes for export/import output flow (diff) | |
download | monero-c5579ac236962ac71cf39bd1928690fe7e1d1899.tar.xz |
allow exporting outputs in chunks
this will make it easier huge wallets to do so without hitting
random limits (eg, max string size in node).
Diffstat (limited to '')
-rw-r--r-- | src/wallet/wallet2.cpp | 94 |
1 files changed, 64 insertions, 30 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 536460396..05d86a817 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6604,9 +6604,9 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s //---------------------------------------------------------------------------------------------------- bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pending_tx> &txs, signed_tx_set &signed_txes) { - if (!exported_txs.new_transfers.second.empty()) + if (!std::get<2>(exported_txs.new_transfers).empty()) import_outputs(exported_txs.new_transfers); - else if (!exported_txs.transfers.second.empty()) + else if (!std::get<2>(exported_txs.transfers).empty()) import_outputs(exported_txs.transfers); // sign the transactions @@ -10800,7 +10800,7 @@ void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_ { txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device())); } - txs.transfers = std::make_pair(0, m_transfers); + txs.transfers = std::make_tuple(0, m_transfers.size(), m_transfers); auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev); CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface"); @@ -13103,18 +13103,29 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx); } //---------------------------------------------------------------------------------------------------- -std::pair<uint64_t, std::vector<tools::wallet2::exported_transfer_details>> wallet2::export_outputs(bool all) const +std::tuple<uint64_t, uint64_t, std::vector<tools::wallet2::exported_transfer_details>> wallet2::export_outputs(bool all, uint32_t start, uint32_t count) const { PERF_TIMER(export_outputs); std::vector<tools::wallet2::exported_transfer_details> outs; + // invalid cases + THROW_WALLET_EXCEPTION_IF(count == 0, error::wallet_internal_error, "Nothing requested"); + THROW_WALLET_EXCEPTION_IF(!all && start > 0, error::wallet_internal_error, "Incremental mode is incompatible with non-zero start"); + + // valid cases: + // all: all outputs, subject to start/count + // !all: incremental, subject to count + // for convenience, start/count are allowed to go past the valid range, then nothing is returned + size_t offset = 0; if (!all) while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request)) ++offset; + else + offset = start; outs.reserve(m_transfers.size() - offset); - for (size_t n = offset; n < m_transfers.size(); ++n) + for (size_t n = offset; n < m_transfers.size() && n - offset < count; ++n) { const transfer_details &td = m_transfers[n]; @@ -13138,16 +13149,16 @@ std::pair<uint64_t, std::vector<tools::wallet2::exported_transfer_details>> wall outs.push_back(etd); } - return std::make_pair(offset, outs); + return std::make_tuple(offset, m_transfers.size(), outs); } //---------------------------------------------------------------------------------------------------- -std::string wallet2::export_outputs_to_str(bool all) const +std::string wallet2::export_outputs_to_str(bool all, uint32_t start, uint32_t count) const { PERF_TIMER(export_outputs_to_str); std::stringstream oss; binary_archive<true> ar(oss); - auto outputs = export_outputs(all); + auto outputs = export_outputs(all, start, count); THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, outputs), error::wallet_internal_error, "Failed to serialize output data"); std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC)); @@ -13160,23 +13171,34 @@ std::string wallet2::export_outputs_to_str(bool all) const return magic + ciphertext; } //---------------------------------------------------------------------------------------------------- -size_t wallet2::import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs) +size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs) { PERF_TIMER(import_outputs); THROW_WALLET_EXCEPTION_IF(!m_offline, error::wallet_internal_error, "Hot wallets cannot import outputs"); - THROW_WALLET_EXCEPTION_IF(outputs.first > m_transfers.size(), error::wallet_internal_error, + // we can now import piecemeal + const size_t offset = std::get<0>(outputs); + const size_t num_outputs = std::get<1>(outputs); + const std::vector<tools::wallet2::transfer_details> &output_array = std::get<2>(outputs); + + THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Imported outputs omit more outputs that we know of"); - const size_t offset = outputs.first; + THROW_WALLET_EXCEPTION_IF(offset >= num_outputs, error::wallet_internal_error, + "Offset is larger than total outputs"); + THROW_WALLET_EXCEPTION_IF(output_array.size() > num_outputs - offset, error::wallet_internal_error, + "Offset is larger than total outputs"); + const size_t original_size = m_transfers.size(); - m_transfers.resize(offset + outputs.second.size()); - for (size_t i = 0; i < offset; ++i) - m_transfers[i].m_key_image_request = false; - for (size_t i = 0; i < outputs.second.size(); ++i) + if (offset + output_array.size() > m_transfers.size()) + m_transfers.resize(offset + output_array.size()); + else if (num_outputs < m_transfers.size()) + m_transfers.resize(num_outputs); + + for (size_t i = 0; i < output_array.size(); ++i) { - transfer_details td = outputs.second[i]; + transfer_details td = output_array[i]; // skip those we've already imported, or which have different data if (i + offset < original_size) @@ -13228,23 +13250,34 @@ process: return m_transfers.size(); } //---------------------------------------------------------------------------------------------------- -size_t wallet2::import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::exported_transfer_details>> &outputs) +size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<tools::wallet2::exported_transfer_details>> &outputs) { PERF_TIMER(import_outputs); THROW_WALLET_EXCEPTION_IF(!m_offline, error::wallet_internal_error, "Hot wallets cannot import outputs"); - THROW_WALLET_EXCEPTION_IF(outputs.first > m_transfers.size(), error::wallet_internal_error, + // we can now import piecemeal + const size_t offset = std::get<0>(outputs); + const size_t num_outputs = std::get<1>(outputs); + const std::vector<tools::wallet2::exported_transfer_details> &output_array = std::get<2>(outputs); + + THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error, "Imported outputs omit more outputs that we know of. Try using export_outputs all."); - const size_t offset = outputs.first; + THROW_WALLET_EXCEPTION_IF(offset >= num_outputs, error::wallet_internal_error, + "Offset is larger than total outputs"); + THROW_WALLET_EXCEPTION_IF(output_array.size() > num_outputs - offset, error::wallet_internal_error, + "Offset is larger than total outputs"); + const size_t original_size = m_transfers.size(); - m_transfers.resize(offset + outputs.second.size()); - for (size_t i = 0; i < offset; ++i) - m_transfers[i].m_key_image_request = false; - for (size_t i = 0; i < outputs.second.size(); ++i) + if (offset + output_array.size() > m_transfers.size()) + m_transfers.resize(offset + output_array.size()); + else if (num_outputs < m_transfers.size()) + m_transfers.resize(num_outputs); + + for (size_t i = 0; i < output_array.size(); ++i) { - exported_transfer_details etd = outputs.second[i]; + exported_transfer_details etd = output_array[i]; transfer_details &td = m_transfers[i + offset]; // setup td with "cheap" loaded data @@ -13358,7 +13391,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) { std::string body(data, headerlen); - std::pair<uint64_t, std::vector<tools::wallet2::exported_transfer_details>> new_outputs; + std::tuple<uint64_t, uint64_t, std::vector<tools::wallet2::exported_transfer_details>> new_outputs; try { binary_archive<false> ar{epee::strspan<std::uint8_t>(body)}; @@ -13368,9 +13401,9 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) } catch (...) {} if (!loaded) - new_outputs.second.clear(); + std::get<2>(new_outputs).clear(); - std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs; + std::tuple<uint64_t, uint64_t, std::vector<tools::wallet2::transfer_details>> outputs; if (!loaded) try { binary_archive<false> ar{epee::strspan<std::uint8_t>(body)}; @@ -13395,11 +13428,12 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) if (!loaded) { - outputs.first = 0; - outputs.second = {}; + std::get<0>(outputs) = 0; + std::get<1>(outputs) = 0; + std::get<2>(outputs) = {}; } - imported_outputs = !new_outputs.second.empty() ? import_outputs(new_outputs) : !outputs.second.empty() ? import_outputs(outputs) : 0; + imported_outputs = !std::get<2>(new_outputs).empty() ? import_outputs(new_outputs) : !std::get<2>(outputs).empty() ? import_outputs(outputs) : 0; } catch (const std::exception &e) { |