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)
This commit is contained in:
parent
7d2d8055ac
commit
d6440ab319
|
@ -1823,7 +1823,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
|
||||||
blocks_added = 0;
|
blocks_added = 0;
|
||||||
|
|
||||||
THROW_WALLET_EXCEPTION_IF(blocks.size() != parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
|
THROW_WALLET_EXCEPTION_IF(blocks.size() != parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
|
||||||
THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain");
|
THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::out_of_hashchain_bounds_error);
|
||||||
|
|
||||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||||
tools::threadpool::waiter waiter;
|
tools::threadpool::waiter waiter;
|
||||||
|
@ -2269,12 +2269,12 @@ void wallet2::update_pool_state(bool refreshed)
|
||||||
MDEBUG("update_pool_state end");
|
MDEBUG("update_pool_state end");
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history)
|
void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force)
|
||||||
{
|
{
|
||||||
std::vector<crypto::hash> hashes;
|
std::vector<crypto::hash> hashes;
|
||||||
|
|
||||||
const uint64_t checkpoint_height = m_checkpoints.get_max_height();
|
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
|
// we will drop all these, so don't bother getting them
|
||||||
uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size();
|
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<cryptonote::block_complete_entry> next_blocks;
|
std::vector<cryptonote::block_complete_entry> next_blocks;
|
||||||
std::vector<parsed_block> next_parsed_blocks;
|
std::vector<parsed_block> next_parsed_blocks;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
added_blocks = 0;
|
||||||
if (!first && blocks.empty())
|
if (!first && blocks.empty())
|
||||||
{
|
{
|
||||||
refreshed = false;
|
refreshed = false;
|
||||||
|
@ -2447,8 +2448,34 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
||||||
tpool.submit(&waiter, [&]{pull_and_parse_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, parsed_blocks, next_blocks, next_parsed_blocks, error);});
|
tpool.submit(&waiter, [&]{pull_and_parse_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, parsed_blocks, next_blocks, next_parsed_blocks, error);});
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
|
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<crypto::hash> 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;
|
blocks_fetched += added_blocks;
|
||||||
}
|
}
|
||||||
waiter.wait(&tpool);
|
waiter.wait(&tpool);
|
||||||
|
@ -2478,6 +2505,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
|
||||||
if(try_count < 3)
|
if(try_count < 3)
|
||||||
{
|
{
|
||||||
LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
|
LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
|
||||||
|
first = true;
|
||||||
++try_count;
|
++try_count;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -1167,7 +1167,7 @@ namespace tools
|
||||||
bool clear();
|
bool clear();
|
||||||
void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices);
|
void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices);
|
||||||
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
|
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
|
||||||
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history);
|
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
|
||||||
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
|
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
|
||||||
void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
|
void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
|
||||||
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const;
|
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const;
|
||||||
|
|
|
@ -70,6 +70,7 @@ namespace tools
|
||||||
// get_out_indexes_error
|
// get_out_indexes_error
|
||||||
// tx_parse_error
|
// tx_parse_error
|
||||||
// get_tx_pool_error
|
// get_tx_pool_error
|
||||||
|
// out_of_hashchain_bounds_error
|
||||||
// transfer_error *
|
// transfer_error *
|
||||||
// get_random_outs_general_error
|
// get_random_outs_general_error
|
||||||
// not_enough_unlocked_money
|
// not_enough_unlocked_money
|
||||||
|
@ -398,6 +399,16 @@ namespace tools
|
||||||
std::string to_string() const { return refresh_error::to_string(); }
|
std::string to_string() const { return refresh_error::to_string(); }
|
||||||
};
|
};
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
struct out_of_hashchain_bounds_error : public refresh_error
|
||||||
|
{
|
||||||
|
explicit out_of_hashchain_bounds_error(std::string&& loc)
|
||||||
|
: refresh_error(std::move(loc), "Index out of bounds of of hashchain")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const { return refresh_error::to_string(); }
|
||||||
|
};
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
struct transfer_error : public wallet_logic_error
|
struct transfer_error : public wallet_logic_error
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in New Issue