aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp62
-rw-r--r--src/wallet/api/wallet.h2
-rw-r--r--src/wallet/api/wallet2_api.h13
-rw-r--r--src/wallet/wallet2.cpp49
-rw-r--r--src/wallet/wallet2.h2
5 files changed, 105 insertions, 23 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index adff042ad..db3049f9e 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1214,6 +1214,68 @@ bool WalletImpl::importKeyImages(const string &filename)
return true;
}
+bool WalletImpl::exportOutputs(const string &filename, bool all)
+{
+ if (m_wallet->key_on_device())
+ {
+ setStatusError(string(tr("Not supported on HW wallets.")) + filename);
+ return false;
+ }
+
+ try
+ {
+ std::string data = m_wallet->export_outputs_to_str(all);
+ bool r = m_wallet->save_to_file(filename, data);
+ if (!r)
+ {
+ LOG_ERROR("Failed to save file " << filename);
+ setStatusError(string(tr("Failed to save file: ")) + filename);
+ return false;
+ }
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Error exporting outputs: " << e.what());
+ setStatusError(string(tr("Error exporting outputs: ")) + e.what());
+ return false;
+ }
+
+ LOG_PRINT_L2("Outputs exported to " << filename);
+ return true;
+}
+
+bool WalletImpl::importOutputs(const string &filename)
+{
+ if (m_wallet->key_on_device())
+ {
+ setStatusError(string(tr("Not supported on HW wallets.")) + filename);
+ return false;
+ }
+
+ std::string data;
+ bool r = m_wallet->load_from_file(filename, data);
+ if (!r)
+ {
+ LOG_ERROR("Failed to read file: " << filename);
+ setStatusError(string(tr("Failed to read file: ")) + filename);
+ return false;
+ }
+
+ try
+ {
+ size_t n_outputs = m_wallet->import_outputs_from_str(data);
+ LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported");
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR("Failed to import outputs: " << e.what());
+ setStatusError(string(tr("Failed to import outputs: ")) + e.what());
+ return false;
+ }
+
+ return true;
+}
+
void WalletImpl::addSubaddressAccount(const std::string& label)
{
m_wallet->add_subaddress_account(label);
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 13b33d1cd..ce2d7d7e4 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -167,6 +167,8 @@ public:
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
bool exportKeyImages(const std::string &filename, bool all = false) override;
bool importKeyImages(const std::string &filename) override;
+ bool exportOutputs(const std::string &filename, bool all = false) override;
+ bool importOutputs(const std::string &filename) override;
virtual void disposeTransaction(PendingTransaction * t) override;
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 320b458bd..e34332734 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -919,6 +919,19 @@ struct Wallet
*/
virtual bool importKeyImages(const std::string &filename) = 0;
+ /*!
+ * \brief importOutputs - exports outputs to file
+ * \param filename
+ * \return - true on success
+ */
+ virtual bool exportOutputs(const std::string &filename, bool all = false) = 0;
+
+ /*!
+ * \brief importOutputs - imports outputs from file
+ * \param filename
+ * \return - true on success
+ */
+ virtual bool importOutputs(const std::string &filename) = 0;
virtual TransactionHistory * history() = 0;
virtual AddressBook * addressBook() = 0;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index c3325c24d..0b310111e 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -12228,7 +12228,7 @@ uint64_t wallet2::get_approximate_blockchain_height() const
// Calculated blockchain height
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
// testnet got some huge rollbacks, so the estimation is way off
- static const uint64_t approximate_testnet_rolled_back_blocks = 303967;
+ static const uint64_t approximate_testnet_rolled_back_blocks = 342100;
if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
@@ -14189,15 +14189,15 @@ void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &h
KECCAK_CTX state;
keccak_init(&state);
keccak_update(&state, (const uint8_t *) transfer.m_txid.data, sizeof(transfer.m_txid.data));
- keccak_update(&state, (const uint8_t *) transfer.m_internal_output_index, sizeof(transfer.m_internal_output_index));
- keccak_update(&state, (const uint8_t *) transfer.m_global_output_index, sizeof(transfer.m_global_output_index));
- keccak_update(&state, (const uint8_t *) transfer.m_amount, sizeof(transfer.m_amount));
+ keccak_update(&state, (const uint8_t *) &transfer.m_internal_output_index, sizeof(transfer.m_internal_output_index));
+ keccak_update(&state, (const uint8_t *) &transfer.m_global_output_index, sizeof(transfer.m_global_output_index));
+ keccak_update(&state, (const uint8_t *) &transfer.m_amount, sizeof(transfer.m_amount));
keccak_finish(&state, (uint8_t *) hash.data);
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const
+uint64_t wallet2::hash_m_transfers(boost::optional<uint64_t> transfer_height, crypto::hash &hash) const
{
- CHECK_AND_ASSERT_THROW_MES(transfer_height > (int64_t)m_transfers.size(), "Hash height is greater than number of transfers");
+ CHECK_AND_ASSERT_THROW_MES(!transfer_height || *transfer_height <= m_transfers.size(), "Hash height is greater than number of transfers");
KECCAK_CTX state;
crypto::hash tmp_hash{};
@@ -14205,12 +14205,12 @@ uint64_t wallet2::hash_m_transfers(int64_t transfer_height, crypto::hash &hash)
keccak_init(&state);
for(const transfer_details & transfer : m_transfers){
- if (transfer_height >= 0 && current_height >= (uint64_t)transfer_height){
+ if (transfer_height && current_height >= *transfer_height){
break;
}
hash_m_transfer(transfer, tmp_hash);
- keccak_update(&state, (const uint8_t *) transfer.m_block_height, sizeof(transfer.m_block_height));
+ keccak_update(&state, (const uint8_t *) &transfer.m_block_height, sizeof(transfer.m_block_height));
keccak_update(&state, (const uint8_t *) tmp_hash.data, sizeof(tmp_hash.data));
current_height += 1;
}
@@ -14222,23 +14222,28 @@ uint64_t wallet2::hash_m_transfers(int64_t transfer_height, crypto::hash &hash)
void wallet2::finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash)
{
// Compute hash of m_transfers, if differs there had to be BC reorg.
- crypto::hash new_transfers_hash{};
- hash_m_transfers((int64_t) transfer_height, new_transfers_hash);
+ if (transfer_height <= m_transfers.size()) {
+ crypto::hash new_transfers_hash{};
+ hash_m_transfers(transfer_height, new_transfers_hash);
- if (new_transfers_hash != hash)
- {
- // Soft-Reset to avoid inconsistency in case of BC reorg.
- clear_soft(false); // keep_key_images works only with soft reset.
- THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Transfers changed during rescan, soft or hard rescan is needed");
- }
+ if (new_transfers_hash == hash) {
+ // Restore key images in m_transfers from m_key_images
+ for(auto it = m_key_images.begin(); it != m_key_images.end(); it++)
+ {
+ THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(),
+ error::wallet_internal_error,
+ "Key images cache contains illegal transfer offset");
+ m_transfers[it->second].m_key_image = it->first;
+ m_transfers[it->second].m_key_image_known = true;
+ }
- // Restore key images in m_transfers from m_key_images
- for(auto it = m_key_images.begin(); it != m_key_images.end(); it++)
- {
- THROW_WALLET_EXCEPTION_IF(it->second >= m_transfers.size(), error::wallet_internal_error, "Key images cache contains illegal transfer offset");
- m_transfers[it->second].m_key_image = it->first;
- m_transfers[it->second].m_key_image_known = true;
+ return;
+ }
}
+
+ // Soft-Reset to avoid inconsistency in case of BC reorg.
+ clear_soft(false); // keep_key_images works only with soft reset.
+ THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Transfers changed during rescan, soft or hard rescan is needed");
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_bytes_sent() const
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index e96a6b51c..facf9878d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1547,7 +1547,7 @@ private:
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_height);
void hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const;
- uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const;
+ uint64_t hash_m_transfers(boost::optional<uint64_t> transfer_height, crypto::hash &hash) const;
void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash);
void enable_dns(bool enable) { m_use_dns = enable; }
void set_offline(bool offline = true);