From d6440ab319ea6adf21485550d6a08ae452d49818 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sat, 28 Apr 2018 12:11:42 +0100 Subject: wallet2: recover from index out of hashchain bounds error This can happen when there's a very large reorg on the daemon (ie, on testnet) --- src/wallet/wallet2.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'src/wallet/wallet2.cpp') diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 40a43b8e7..66188b823 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1823,7 +1823,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector &short_chain_history) +void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list &short_chain_history, bool force) { std::vector hashes; const uint64_t checkpoint_height = m_checkpoints.get_max_height(); - if (stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) + if ((stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) && !force) { // we will drop all these, so don't bother getting them uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size(); @@ -2439,6 +2439,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo std::vector next_blocks; std::vector next_parsed_blocks; bool error = false; + added_blocks = 0; if (!first && blocks.empty()) { refreshed = false; @@ -2448,7 +2449,33 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo if (!first) { - process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks); + try + { + process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks); + } + catch (const tools::error::out_of_hashchain_bounds_error&) + { + MINFO("Daemon claims next refresh block is out of hash chain bounds, resetting hash chain"); + uint64_t stop_height = m_blockchain.offset(); + std::vector tip(m_blockchain.size() - m_blockchain.offset()); + for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); ++i) + tip[i - m_blockchain.offset()] = m_blockchain[i]; + cryptonote::block b; + generate_genesis(b); + m_blockchain.clear(); + m_blockchain.push_back(get_block_hash(b)); + short_chain_history.clear(); + get_short_chain_history(short_chain_history); + fast_refresh(stop_height, blocks_start_height, short_chain_history, true); + THROW_WALLET_EXCEPTION_IF(m_blockchain.size() != stop_height, error::wallet_internal_error, "Unexpected hashchain size"); + THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error, "Unexpected hashchain offset"); + for (const auto &h: tip) + m_blockchain.push_back(h); + short_chain_history.clear(); + get_short_chain_history(short_chain_history); + start_height = stop_height; + throw std::runtime_error(""); // loop again + } blocks_fetched += added_blocks; } waiter.wait(&tpool); @@ -2478,6 +2505,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo if(try_count < 3) { LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")..."); + first = true; ++try_count; } else -- cgit v1.2.3