From d6e3ffa3d6fb4ab2235fc108728e16b1c8be0690 Mon Sep 17 00:00:00 2001 From: aiwe Date: Tue, 30 Apr 2024 23:06:40 -0500 Subject: [PATCH] Wallet synchronization enhancements --- src/Transfers/TransfersConsumer.cpp | 192 ++++++++++++++++++--------- src/Transfers/TransfersContainer.cpp | 135 ++++++++++++------- 2 files changed, 216 insertions(+), 111 deletions(-) diff --git a/src/Transfers/TransfersConsumer.cpp b/src/Transfers/TransfersConsumer.cpp index b276e1d7f7..35e186f474 100644 --- a/src/Transfers/TransfersConsumer.cpp +++ b/src/Transfers/TransfersConsumer.cpp @@ -1,7 +1,7 @@ -// Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers -// Copyright (c) 2018, The BBSCoin Developers -// Copyright (c) 2018, The Karbo Developers -// +// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers. +// Copyright (c) 2018 BBSCoin developers +// Copyright (c) 2018-2019, The Karbo Developers +// // This file is part of Karbo. // // Karbo is free software: you can redistribute it and/or modify @@ -23,8 +23,8 @@ #include #include "CommonTypes.h" -#include "Common/StringTools.h" #include "Common/BlockingQueue.h" +#include "CryptoNoteCore/CryptoNoteBasicImpl.h" #include "CryptoNoteCore/CryptoNoteFormatUtils.h" #include "CryptoNoteCore/TransactionApi.h" @@ -35,6 +35,7 @@ using namespace Crypto; using namespace Logging; using namespace Common; + std::unordered_set transactions_hash_seen; std::unordered_set public_keys_seen; std::mutex seen_mutex; @@ -43,6 +44,19 @@ namespace { using namespace CryptoNote; +class MarkTransactionConfirmedException : public std::exception { +public: + MarkTransactionConfirmedException(const Crypto::Hash& txHash) { + } + + const Hash& getTxHash() const { + return m_txHash; + } + +private: + Crypto::Hash m_txHash; +}; + void checkOutputKey( const KeyDerivation& derivation, const PublicKey& key, @@ -85,7 +99,6 @@ void findMyOutputs( uint64_t amount; KeyOutput out; tx.getOutput(idx, out, amount); - checkOutputKey(derivation, out.key, keyIndex, idx, spendKeys, outputs); ++keyIndex; @@ -94,10 +107,8 @@ void findMyOutputs( uint64_t amount; MultisignatureOutput out; tx.getOutput(idx, out, amount); - for (const auto& key : out.keys) { checkOutputKey(derivation, key, idx, idx, spendKeys, outputs); - ++keyIndex; } } @@ -134,9 +145,11 @@ ITransfersSubscription& TransfersConsumer::addSubscription(const AccountSubscrip if (res.get() == nullptr) { res.reset(new TransfersSubscription(m_currency, m_logger.getLogger(), subscription)); m_spendKeys.insert(subscription.keys.address.spendPublicKey); + if (m_subscriptions.size() == 1) { m_syncStart = res->getSyncStart(); - } else { + } + else { auto subStart = res->getSyncStart(); m_syncStart.height = std::min(m_syncStart.height, subStart.height); m_syncStart.timestamp = std::min(m_syncStart.timestamp, subStart.timestamp); @@ -180,7 +193,7 @@ void TransfersConsumer::initTransactionPool(const std::unordered_set::max(); + start.height = std::numeric_limits::max(); start.timestamp = std::numeric_limits::max(); for (const auto& kv : m_subscriptions) { @@ -204,13 +217,14 @@ void TransfersConsumer::onBlockchainDetach(uint32_t height) { } } -bool TransfersConsumer::onNewBlocks(const CompleteBlock* blocks, uint32_t startHeight, uint32_t count) { +uint32_t TransfersConsumer::onNewBlocks(const CompleteBlock* blocks, uint32_t startHeight, uint32_t count) { assert(blocks); assert(count > 0); struct Tx { TransactionBlockInfo blockInfo; const ITransactionReader* tx; + bool isLastTransactionInBlock; }; struct PreprocessedTx : Tx, PreprocessInfo {}; @@ -226,17 +240,20 @@ bool TransfersConsumer::onNewBlocks(const CompleteBlock* blocks, uint32_t startH BlockingQueue inputQueue(workers * 2); std::atomic stopProcessing(false); + std::atomic emptyBlockCount(0); auto pushingThread = std::async(std::launch::async, [&] { - for( uint32_t i = 0; i < count && !stopProcessing; ++i) { + for (uint32_t i = 0; i < count && !stopProcessing; ++i) { const auto& block = blocks[i].block; if (!block.is_initialized()) { + ++emptyBlockCount; continue; } // filter by syncStartTimestamp if (m_syncStart.timestamp && block->timestamp < m_syncStart.timestamp) { + ++emptyBlockCount; continue; } @@ -252,7 +269,8 @@ bool TransfersConsumer::onNewBlocks(const CompleteBlock* blocks, uint32_t startH continue; } - Tx item = { blockInfo, tx.get() }; + bool isLastTransactionInBlock = blockInfo.transactionIndex + 1 == blocks[i].transactions.size(); + Tx item = { blockInfo, tx.get(), isLastTransactionInBlock }; inputQueue.push(item); ++blockInfo.transactionIndex; } @@ -299,37 +317,68 @@ bool TransfersConsumer::onNewBlocks(const CompleteBlock* blocks, uint32_t startH } } + if (processingError) { + forEachSubscription([&](TransfersSubscription& sub) { + sub.onError(processingError, startHeight); + }); + + return 0; + } + std::vector blockHashes = getBlockHashes(blocks, count); - if (!processingError) { - m_observerManager.notify(&IBlockchainConsumerObserver::onBlocksAdded, this, blockHashes); + m_observerManager.notify(&IBlockchainConsumerObserver::onBlocksAdded, this, blockHashes); - // sort by block height and transaction index in block - std::sort(preprocessedTransactions.begin(), preprocessedTransactions.end(), [](const PreprocessedTx& a, const PreprocessedTx& b) { - return std::tie(a.blockInfo.height, a.blockInfo.transactionIndex) < std::tie(b.blockInfo.height, b.blockInfo.transactionIndex); - }); + // sort by block height and transaction index in block + std::sort(preprocessedTransactions.begin(), preprocessedTransactions.end(), [](const PreprocessedTx& a, const PreprocessedTx& b) { + return std::tie(a.blockInfo.height, a.blockInfo.transactionIndex) < std::tie(b.blockInfo.height, b.blockInfo.transactionIndex); + }); + uint32_t processedBlockCount = static_cast(emptyBlockCount); + try { for (const auto& tx : preprocessedTransactions) { processTransaction(tx.blockInfo, *tx.tx, tx); + + if (tx.isLastTransactionInBlock) { + ++processedBlockCount; + m_logger(TRACE) << "Processed block " << processedBlockCount << " of " << count << ", last processed block index " << tx.blockInfo.height << + ", hash " << blocks[processedBlockCount - 1].blockHash; + + auto newHeight = startHeight + processedBlockCount - 1; + forEachSubscription([newHeight](TransfersSubscription& sub) { + sub.advanceHeight(newHeight); + }); + } } - } else { - forEachSubscription([&](TransfersSubscription& sub) { - sub.onError(processingError, startHeight); + } catch (const MarkTransactionConfirmedException& e) { + m_logger(ERROR, BRIGHT_RED) << "Failed to process block transactions: failed to confirm transaction " << e.getTxHash() << + ", remove this transaction from all containers and transaction pool"; + forEachSubscription([&e](TransfersSubscription& sub) { + sub.deleteUnconfirmedTransaction(e.getTxHash()); }); - return false; + m_poolTxs.erase(e.getTxHash()); + } catch (std::exception& e) { + m_logger(ERROR, BRIGHT_RED) << "Failed to process block transactions, exception: " << e.what(); + } catch (...) { + m_logger(ERROR, BRIGHT_RED) << "Failed to process block transactions, unknown exception"; } - auto newHeight = startHeight + count - 1; - forEachSubscription([newHeight](TransfersSubscription& sub) { - sub.advanceHeight(newHeight); - }); + if (processedBlockCount < count) { + uint32_t detachIndex = startHeight + processedBlockCount; + m_logger(ERROR, BRIGHT_RED) << "Not all block transactions are processed, fully processed block count: " << processedBlockCount << " of " << count << + ", last processed block hash " << (processedBlockCount > 0 ? blocks[processedBlockCount - 1].blockHash : NULL_HASH) << + ", detach block index " << detachIndex << " to remove partially processed block"; + forEachSubscription([detachIndex](TransfersSubscription& sub) { + sub.onBlockchainDetach(detachIndex); + }); + } - return true; + return processedBlockCount; } std::error_code TransfersConsumer::onPoolUpdated(const std::vector>& addedTransactions, const std::vector& deletedTransactions) { TransactionBlockInfo unconfirmedBlockInfo; - unconfirmedBlockInfo.timestamp = 0; + unconfirmedBlockInfo.timestamp = 0; unconfirmedBlockInfo.height = WALLET_UNCONFIRMED_TRANSACTION_HEIGHT; std::error_code processingError; @@ -344,7 +393,7 @@ std::error_code TransfersConsumer::onPoolUpdated(const std::vector lk(seen_mutex); - transactions_hash_seen.insert(transactionHash); - public_keys_seen.insert(outputKey); + std::lock_guard lk(seen_mutex); + transactions_hash_seen.insert(transactionHash); + public_keys_seen.insert(outputKey); } -std::error_code TransfersConsumer::createTransfers( +std::error_code createTransfers( const AccountKeys& account, const TransactionBlockInfo& blockInfo, const ITransactionReader& tx, const std::vector& outputs, const std::vector& globalIdxs, - std::vector& transfers) { + std::vector& transfers, + Logging::LoggerRef& m_logger) { auto txPubKey = tx.getTransactionPublicKey(); auto txHash = tx.getTransactionHash(); std::vector temp_keys; std::lock_guard lk(seen_mutex); - if (account.spendSecretKey == NULL_SECRET_KEY) { - KeyPair deterministic_tx_keys; - bool spending = generateDeterministicTransactionKeys(tx.getTransactionInputsHash(), account.viewSecretKey, deterministic_tx_keys) - && deterministic_tx_keys.publicKey == txPubKey; - - if (spending) { - m_logger(WARNING, BRIGHT_YELLOW) << "Spending in tx " << Common::podToHex(tx.getTransactionHash()); - } - } - for (auto idx : outputs) { if (idx >= tx.getOutputCount()) { @@ -447,18 +487,18 @@ std::error_code TransfersConsumer::createTransfers( assert(out.key == reinterpret_cast(in_ephemeral.publicKey)); std::unordered_set::iterator it = transactions_hash_seen.find(txHash); - if (it == transactions_hash_seen.end()) { + if (it == transactions_hash_seen.end()) { std::unordered_set::iterator key_it = public_keys_seen.find(out.key); if (key_it != public_keys_seen.end()) { - m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction " << Common::podToHex(txHash) << ": duplicate output key is found!"; + throw std::runtime_error("duplicate transaction output key is found"); return std::error_code(); } if (std::find(temp_keys.begin(), temp_keys.end(), out.key) != temp_keys.end()) { - m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction " << Common::podToHex(txHash) << ": the same output key is present more than once"; + throw std::runtime_error("the same output key is present more than once"); return std::error_code(); } temp_keys.push_back(out.key); - } + } info.amount = amount; info.outputKey = out.key; @@ -467,16 +507,16 @@ std::error_code TransfersConsumer::createTransfers( MultisignatureOutput out; tx.getOutput(idx, out, amount); - for (const auto& key : out.keys) { + for (const auto& key : out.keys) { std::unordered_set::iterator it = transactions_hash_seen.find(txHash); if (it == transactions_hash_seen.end()) { std::unordered_set::iterator key_it = public_keys_seen.find(key); if (key_it != public_keys_seen.end()) { - m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction " << Common::podToHex(txHash) << ": duplicate multisignature output key is found"; + throw std::runtime_error("duplicate multisignature output key is found"); return std::error_code(); } if (std::find(temp_keys.begin(), temp_keys.end(), key) != temp_keys.end()) { - m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction " << Common::podToHex(txHash) << ": the same multisignature output key is present more than once"; + throw std::runtime_error("the same multisignature output key is present more than once"); return std::error_code(); } temp_keys.push_back(key); @@ -485,19 +525,27 @@ std::error_code TransfersConsumer::createTransfers( info.amount = amount; info.requiredSignatures = out.requiredSignatureCount; } - transfers.push_back(info); } - transactions_hash_seen.emplace(txHash); - std::copy(temp_keys.begin(), temp_keys.end(), std::inserter(public_keys_seen, public_keys_seen.end())); + transactions_hash_seen.insert(tx.getTransactionHash()); + for (std::vector::iterator it = temp_keys.begin(); it != temp_keys.end(); it++) { + public_keys_seen.insert(*it); + } return std::error_code(); } std::error_code TransfersConsumer::preprocessOutputs(const TransactionBlockInfo& blockInfo, const ITransactionReader& tx, PreprocessInfo& info) { std::unordered_map> outputs; - findMyOutputs(tx, m_viewSecret, m_spendKeys, outputs); + try { + findMyOutputs(tx, m_viewSecret, m_spendKeys, outputs); + } + catch (const std::exception& e) { + m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction: " << e.what() << ", transaction hash " << Common::podToHex(tx.getTransactionHash()); + return std::error_code(); + } + if (outputs.empty()) { return std::error_code(); } @@ -515,9 +563,15 @@ std::error_code TransfersConsumer::preprocessOutputs(const TransactionBlockInfo& auto it = m_subscriptions.find(kv.first); if (it != m_subscriptions.end()) { auto& transfers = info.outputs[kv.first]; - errorCode = createTransfers(it->second->getKeys(), blockInfo, tx, kv.second, info.globalIdxs, transfers); - if (errorCode) { - return errorCode; + try { + errorCode = createTransfers(it->second->getKeys(), blockInfo, tx, kv.second, info.globalIdxs, transfers, m_logger); + if (errorCode) { + return errorCode; + } + } + catch (const std::exception& e) { + m_logger(ERROR, BRIGHT_RED) << "Failed to process transaction: " << e.what() << ", transaction hash " << Common::podToHex(tx.getTransactionHash()); + return std::error_code(); } } } @@ -539,6 +593,8 @@ std::error_code TransfersConsumer::processTransaction(const TransactionBlockInfo void TransfersConsumer::processTransaction(const TransactionBlockInfo& blockInfo, const ITransactionReader& tx, const PreprocessInfo& info) { std::vector emptyOutputs; std::vector transactionContainers; + + m_logger(TRACE) << "Process transaction, block " << blockInfo.height << ", transaction index " << blockInfo.transactionIndex << ", hash " << tx.getTransactionHash(); bool someContainerUpdated = false; for (auto& kv : m_subscriptions) { auto it = info.outputs.find(kv.first); @@ -554,7 +610,10 @@ void TransfersConsumer::processTransaction(const TransactionBlockInfo& blockInfo } if (someContainerUpdated) { + m_logger(TRACE) << "Transaction updated some containers, hash " << tx.getTransactionHash(); m_observerManager.notify(&IBlockchainConsumerObserver::onTransactionUpdated, this, tx.getTransactionHash(), transactionContainers); + } else { + m_logger(TRACE) << "Transaction doesn't updated any container, hash " << tx.getTransactionHash(); } } @@ -567,9 +626,14 @@ void TransfersConsumer::processOutputs(const TransactionBlockInfo& blockInfo, Tr if (contains) { if (subscriptionTxInfo.blockHeight == WALLET_UNCONFIRMED_TRANSACTION_HEIGHT && blockInfo.height != WALLET_UNCONFIRMED_TRANSACTION_HEIGHT) { - // pool->blockchain - sub.markTransactionConfirmed(blockInfo, tx.getTransactionHash(), globalIdxs); - updated = true; + try { + // pool->blockchain + sub.markTransactionConfirmed(blockInfo, tx.getTransactionHash(), globalIdxs); + updated = true; + } catch (...) { + m_logger(ERROR, BRIGHT_RED) << "markTransactionConfirmed failed, throw MarkTransactionConfirmedException"; + throw MarkTransactionConfirmedException(tx.getTransactionHash()); + } } else { assert(subscriptionTxInfo.blockHeight == blockInfo.height); } @@ -579,11 +643,11 @@ void TransfersConsumer::processOutputs(const TransactionBlockInfo& blockInfo, Tr } } -std::error_code TransfersConsumer::getGlobalIndices(const Hash& transactionHash, std::vector& outsGlobalIndices) { +std::error_code TransfersConsumer::getGlobalIndices(const Hash& transactionHash, std::vector& outsGlobalIndices) { std::promise prom; std::future f = prom.get_future(); - INode::Callback cb = [&prom](std::error_code ec) { + INode::Callback cb = [&prom](std::error_code ec) { std::promise p(std::move(prom)); p.set_value(ec); }; diff --git a/src/Transfers/TransfersContainer.cpp b/src/Transfers/TransfersContainer.cpp index e82403242b..3366a58372 100644 --- a/src/Transfers/TransfersContainer.cpp +++ b/src/Transfers/TransfersContainer.cpp @@ -1,4 +1,5 @@ -// Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers +// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers +// Copyright (c) 2016-2020, The Karbo developers // // This file is part of Karbo. // @@ -181,8 +182,6 @@ bool TransfersContainer::addTransaction(const TransactionBlockInfo& block, const try { std::unique_lock lock(m_mutex); - m_logger(TRACE) << "Adding transaction, block " << block.height << ", transaction index " << block.transactionIndex << ", hash " << tx.getTransactionHash(); - if (block.height < m_currentHeight) { auto message = "Failed to add transaction: block index < m_currentHeight"; m_logger(ERROR, BRIGHT_RED) << message << ", block " << block.height << ", m_currentHeight " << m_currentHeight; @@ -200,8 +199,6 @@ bool TransfersContainer::addTransaction(const TransactionBlockInfo& block, const if (added) { addTransaction(block, tx); - } else { - m_logger(TRACE) << "Transaction not added"; } if (block.height != WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT) { @@ -457,56 +454,99 @@ bool TransfersContainer::markTransactionConfirmed(const TransactionBlockInfo& bl return false; } - auto txInfo = *transactionIt; - txInfo.blockHeight = block.height; - txInfo.timestamp = block.timestamp; - m_transactions.replace(transactionIt, txInfo); - - auto availableRange = m_unconfirmedTransfers.get().equal_range(transactionHash); - for (auto transferIt = availableRange.first; transferIt != availableRange.second; ) { - auto transfer = *transferIt; - assert(transfer.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT); - assert(transfer.globalOutputIndex == UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX); - if (transfer.outputInTransaction >= globalIndices.size()) { - auto message = "Failed to confirm transaction: not enough elements in globalIndices"; - m_logger(ERROR, BRIGHT_RED) << message << ", globalIndices.size() " << globalIndices.size() << ", output index " << transfer.outputInTransaction; - throw std::invalid_argument(message); - } + try { + auto txInfo = *transactionIt; + txInfo.blockHeight = block.height; + txInfo.timestamp = block.timestamp; + m_transactions.replace(transactionIt, txInfo); + + auto availableRange = m_unconfirmedTransfers.get().equal_range(transactionHash); + for (auto transferIt = availableRange.first; transferIt != availableRange.second; ) { + auto transfer = *transferIt; + assert(transfer.blockHeight == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT); + assert(transfer.globalOutputIndex == UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX); + if (transfer.outputInTransaction >= globalIndices.size()) { + auto message = "Failed to confirm transaction: not enough elements in globalIndices"; + m_logger(ERROR, BRIGHT_RED) << message << ", globalIndices.size() " << globalIndices.size() << ", output index " << transfer.outputInTransaction; + throw std::invalid_argument(message); + } - transfer.blockHeight = block.height; - transfer.transactionIndex = block.transactionIndex; - transfer.globalOutputIndex = globalIndices[transfer.outputInTransaction]; - - if (transfer.type == TransactionTypes::OutputType::Multisignature) { - SpentOutputDescriptor descriptor(transfer); - if (m_availableTransfers.get().count(descriptor) > 0 || - m_spentTransfers.get().count(descriptor) > 0) { - // This exception breaks TransfersContainer consistency - auto message = "Failed to confirm transaction: multisignature output already exists"; - m_logger(ERROR, BRIGHT_RED) << message << ", amount " << m_currency.formatAmount(transfer.amount) << ", global index " << transfer.globalOutputIndex; - throw std::runtime_error(message); + transfer.blockHeight = block.height; + transfer.transactionIndex = block.transactionIndex; + transfer.globalOutputIndex = globalIndices[transfer.outputInTransaction]; + + if (transfer.type == TransactionTypes::OutputType::Multisignature) { + SpentOutputDescriptor descriptor(transfer); + if (m_availableTransfers.get().count(descriptor) > 0 || + m_spentTransfers.get().count(descriptor) > 0) { + // This exception breaks TransfersContainer consistency + auto message = "Failed to confirm transaction: multisignature output already exists"; + m_logger(ERROR, BRIGHT_RED) << message << ", amount " << m_currency.formatAmount(transfer.amount) << ", global index " << transfer.globalOutputIndex; + throw std::runtime_error(message); + } + } + + auto result = m_availableTransfers.emplace(std::move(transfer)); + (void)result; // Disable unused warning + assert(result.second); + + transferIt = m_unconfirmedTransfers.get().erase(transferIt); + + if (transfer.type == TransactionTypes::OutputType::Key) { + updateTransfersVisibility(transfer.keyImage); } } - auto result = m_availableTransfers.emplace(std::move(transfer)); - (void)result; // Disable unused warning - assert(result.second); + auto& spendingTransactionIndex = m_spentTransfers.get(); + auto spentRange = spendingTransactionIndex.equal_range(transactionHash); + for (auto transferIt = spentRange.first; transferIt != spentRange.second; ++transferIt) { + auto transfer = *transferIt; + assert(transfer.spendingBlock.height == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT); + + transfer.spendingBlock = block; + spendingTransactionIndex.replace(transferIt, transfer); + } + } catch (std::exception& e) { + m_logger(ERROR, BRIGHT_RED) << "markTransactionConfirmed failed: " << e.what() << ", rollback changes, block index " << block.height << + ", tx " << transactionHash; + + auto txInfo = *transactionIt; + txInfo.blockHeight = WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT; + txInfo.timestamp = 0; + m_transactions.replace(transactionIt, txInfo); + + auto availableRange = m_availableTransfers.get().equal_range(transactionHash); + for (auto transferIt = availableRange.first; transferIt != availableRange.second; ) { + TransactionOutputInformationEx unconfirmedTransfer = *transferIt; + assert(unconfirmedTransfer.blockHeight != WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT); + assert(unconfirmedTransfer.globalOutputIndex != UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX); + unconfirmedTransfer.blockHeight = WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT; + unconfirmedTransfer.transactionIndex = 0; + unconfirmedTransfer.globalOutputIndex = UNCONFIRMED_TRANSACTION_GLOBAL_OUTPUT_INDEX; + + auto result = m_unconfirmedTransfers.emplace(std::move(unconfirmedTransfer)); + (void)result; // Disable unused warning + assert(result.second); - transferIt = m_unconfirmedTransfers.get().erase(transferIt); + transferIt = m_availableTransfers.get().erase(transferIt); - if (transfer.type == TransactionTypes::OutputType::Key) { - updateTransfersVisibility(transfer.keyImage); + if (unconfirmedTransfer.type == TransactionTypes::OutputType::Key) { + updateTransfersVisibility(unconfirmedTransfer.keyImage); + } } - } - auto& spendingTransactionIndex = m_spentTransfers.get(); - auto spentRange = spendingTransactionIndex.equal_range(transactionHash); - for (auto transferIt = spentRange.first; transferIt != spentRange.second; ++transferIt) { - auto transfer = *transferIt; - assert(transfer.spendingBlock.height == WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT); + auto& spendingTransactionIndex = m_spentTransfers.get(); + auto spentRange = spendingTransactionIndex.equal_range(transactionHash); + for (auto transferIt = spentRange.first; transferIt != spentRange.second; ++transferIt) { + auto spentTransfer = *transferIt; + spentTransfer.spendingBlock.height = WALLET_LEGACY_UNCONFIRMED_TRANSACTION_HEIGHT; + spentTransfer.spendingBlock.timestamp = 0; + spentTransfer.spendingBlock.transactionIndex = 0; + + spendingTransactionIndex.replace(transferIt, spentTransfer); + } - transfer.spendingBlock = block; - spendingTransactionIndex.replace(transferIt, transfer); + throw; } return true; @@ -896,7 +936,8 @@ void TransfersContainer::load(std::istream& in) { m_spentTransfers = std::move(spentTransfers); // Repair the container if it was broken while handling addTransaction() in previous version of the code - repair(); + // Hope it isn't necessary anymore + //repair(); } void TransfersContainer::repair() {