From 089df4af831520e0a16b643b876da37222bf4663 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 16 Jun 2016 23:58:54 +0100 Subject: [PATCH] wallet: reset output spent status on blockchain reorg If the blockchain gets reorganized, all outputs spent in the part of the blockchain that's blown away need to be reset to unspent (they may end up spent again on the blocks that replace the blocks that are removed, however). --- src/wallet/wallet2.cpp | 46 +++++++++++++++++++++++++++++++++++++----- src/wallet/wallet2.h | 26 ++++++++++++++++++------ 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 76731545..55106fa9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -490,6 +490,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << get_transaction_hash(tx)); tx_money_spent_in_ins += amount; td.m_spent = true; + td.m_spent_height = height; if (0 != m_callback) m_callback->on_money_spent(height, td.m_tx, amount, tx); } @@ -1167,6 +1168,17 @@ void wallet2::detach_blockchain(uint64_t height) LOG_PRINT_L0("Detaching blockchain on height " << height); size_t transfers_detached = 0; + for (size_t i = 0; i < m_transfers.size(); ++i) + { + wallet2::transfer_details &td = m_transfers[i]; + if (td.m_spent && td.m_spent_height >= height) + { + LOG_PRINT_L1("Resetting spent status for output " << i << ": " << td.m_key_image); + td.m_spent = false; + td.m_spent_height = 0; + } + } + auto it = std::find_if(m_transfers.begin(), m_transfers.end(), [&](const transfer_details& td){return td.m_block_height >= height;}); size_t i_start = it - m_transfers.begin(); @@ -1980,10 +1992,12 @@ void wallet2::rescan_spent() if (td.m_spent) { LOG_PRINT_L0("Marking output " << i << "(" << td.m_key_image << ") as unspent, it was marked as spent"); + td.m_spent_height = 0; } else { LOG_PRINT_L0("Marking output " << i << "(" << td.m_key_image << ") as spent, it was marked as unspent"); + // unknown height, if this gets reorged, it might still be missed } td.m_spent = daemon_resp.spent_status[i] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT; } @@ -2293,7 +2307,10 @@ void wallet2::commit_tx(pending_tx& ptx) LOG_PRINT_L2("transaction " << txid << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]"); BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers) + { it->m_spent = true; + it->m_spent_height = 0; + } //fee includes dust if dust policy specified it. LOG_PRINT_L0("Transaction successfully sent. <" << txid << ">" << ENDL @@ -2371,7 +2388,10 @@ std::vector wallet2::create_transactions(std::vectorm_spent = true; + it->m_spent_height = 0; + } } // if we made it this far, we've selected our transactions. committing them will mark them spent, @@ -2381,7 +2401,10 @@ std::vector wallet2::create_transactions(std::vectorm_spent = false; + it2->m_spent_height = 0; + } } @@ -2398,8 +2421,10 @@ std::vector wallet2::create_transactions(std::vectorm_spent = false; - + it2->m_spent_height = 0; + } } if (attempt_count >= MAX_SPLIT_ATTEMPTS) @@ -2416,8 +2441,10 @@ std::vector wallet2::create_transactions(std::vectorm_spent = false; - + it2->m_spent_height = 0; + } } throw; @@ -3860,7 +3887,10 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo // mark transfers to be used as "spent" BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers) + { it->m_spent = true; + it->m_spent_height = 0; + } } // if we made it this far, we've selected our transactions. committing them will mark them spent, @@ -3870,8 +3900,10 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo { // mark transfers to be used as not spent BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers) + { it2->m_spent = false; - + it2->m_spent_height = 0; + } } // if we made it this far, we're OK to actually send the transactions @@ -3887,8 +3919,10 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo { // mark transfers to be used as not spent BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers) + { it2->m_spent = false; - + it2->m_spent_height = 0; + } } if (attempt_count >= MAX_SPLIT_ATTEMPTS) @@ -3905,8 +3939,10 @@ std::vector wallet2::create_unmixable_sweep_transactions(bo { // mark transfers to be used as not spent BOOST_FOREACH(transfer_container::iterator it2, ptx.selected_transfers) + { it2->m_spent = false; - + it2->m_spent_height = 0; + } } throw; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 125f8edb..1c835429 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -103,6 +103,7 @@ namespace tools size_t m_internal_output_index; uint64_t m_global_output_index; bool m_spent; + uint64_t m_spent_height; crypto::key_image m_key_image; //TODO: key_image stored twice :( rct::key m_mask; uint64_t m_amount; @@ -490,7 +491,7 @@ namespace tools }; } BOOST_CLASS_VERSION(tools::wallet2, 13) -BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 1) +BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 2) BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 4) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 2) @@ -500,14 +501,21 @@ namespace boost namespace serialization { template - inline void initialize_transfer_details(Archive &a, tools::wallet2::transfer_details &x) + inline void initialize_transfer_details(Archive &a, tools::wallet2::transfer_details &x, const boost::serialization::version_type ver) { } template<> - inline void initialize_transfer_details(boost::archive::binary_iarchive &a, tools::wallet2::transfer_details &x) + inline void initialize_transfer_details(boost::archive::binary_iarchive &a, tools::wallet2::transfer_details &x, const boost::serialization::version_type ver) { - x.m_mask = rct::identity(); - x.m_amount = x.m_tx.vout[x.m_internal_output_index].amount; + if (ver < 1) + { + x.m_mask = rct::identity(); + x.m_amount = x.m_tx.vout[x.m_internal_output_index].amount; + } + if (ver < 2) + { + x.m_spent_height = 0; + } } template @@ -522,11 +530,17 @@ namespace boost if (ver < 1) { // ensure mask and amount are set - initialize_transfer_details(a, x); + initialize_transfer_details(a, x, ver); return; } a & x.m_mask; a & x.m_amount; + if (ver < 2) + { + initialize_transfer_details(a, x, ver); + return; + } + a & x.m_spent_height; } template