Merge pull request #2372

c867357a cryptonote_protocol: error handling on cleanup_handle_incoming_blocks (moneromooo-monero)
ce901fcb Fix blockchain_import wedge on exception in cleanup_handle_incoming_blocks (moneromooo-monero)
84fa015e core: guard against exceptions in handle_incoming_{block,tx} (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2017-09-02 11:30:57 +02:00
commit 1e57e48342
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD
6 changed files with 89 additions and 21 deletions

View File

@ -2604,6 +2604,16 @@ void BlockchainLMDB::batch_commit()
memset(&m_wcursors, 0, sizeof(m_wcursors)); memset(&m_wcursors, 0, sizeof(m_wcursors));
} }
void BlockchainLMDB::cleanup_batch()
{
// for destruction of batch transaction
m_write_txn = nullptr;
delete m_write_batch_txn;
m_write_batch_txn = nullptr;
m_batch_active = false;
memset(&m_wcursors, 0, sizeof(m_wcursors));
}
void BlockchainLMDB::batch_stop() void BlockchainLMDB::batch_stop()
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -2618,15 +2628,18 @@ void BlockchainLMDB::batch_stop()
check_open(); check_open();
LOG_PRINT_L3("batch transaction: committing..."); LOG_PRINT_L3("batch transaction: committing...");
TIME_MEASURE_START(time1); TIME_MEASURE_START(time1);
try
{
m_write_txn->commit(); m_write_txn->commit();
TIME_MEASURE_FINISH(time1); TIME_MEASURE_FINISH(time1);
time_commit1 += time1; time_commit1 += time1;
// for destruction of batch transaction cleanup_batch();
m_write_txn = nullptr; }
delete m_write_batch_txn; catch (const std::exception &e)
m_write_batch_txn = nullptr; {
m_batch_active = false; cleanup_batch();
memset(&m_wcursors, 0, sizeof(m_wcursors)); throw;
}
LOG_PRINT_L3("batch transaction: end"); LOG_PRINT_L3("batch transaction: end");
} }

View File

@ -368,6 +368,9 @@ private:
// migrate from DB version 0 to 1 // migrate from DB version 0 to 1
void migrate_0_1(); void migrate_0_1();
void cleanup_batch();
private:
MDB_env* m_env; MDB_env* m_env;
MDB_dbi m_blocks; MDB_dbi m_blocks;

View File

@ -208,7 +208,8 @@ int check_flush(cryptonote::core &core, std::list<block_complete_entry> &blocks,
} }
} // each download block } // each download block
core.cleanup_handle_incoming_blocks(); if (!core.cleanup_handle_incoming_blocks())
return 1;
blocks.clear(); blocks.clear();
return 0; return 0;
@ -394,8 +395,11 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
blocks.push_back({block, txs}); blocks.push_back({block, txs});
int ret = check_flush(core, blocks, false); int ret = check_flush(core, blocks, false);
if (ret) if (ret)
{
quit = 2; // make sure we don't commit partial block data
break; break;
} }
}
else else
{ {
std::vector<transaction> txs; std::vector<transaction> txs;

View File

@ -3582,12 +3582,23 @@ void Blockchain::block_longhash_worker(uint64_t height, const std::vector<block>
//------------------------------------------------------------------ //------------------------------------------------------------------
bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
{ {
bool success = false;
MTRACE("Blockchain::" << __func__); MTRACE("Blockchain::" << __func__);
CRITICAL_REGION_BEGIN(m_blockchain_lock); CRITICAL_REGION_BEGIN(m_blockchain_lock);
TIME_MEASURE_START(t1); TIME_MEASURE_START(t1);
try
{
m_db->batch_stop(); m_db->batch_stop();
if (m_sync_counter > 0) success = true;
}
catch (const std::exception &e)
{
MERROR("Exception in cleanup_handle_incoming_blocks: " << e.what());
}
if (success && m_sync_counter > 0)
{ {
if (force_sync) if (force_sync)
{ {
@ -3622,7 +3633,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
CRITICAL_REGION_END(); CRITICAL_REGION_END();
m_tx_pool.unlock(); m_tx_pool.unlock();
return true; return success;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -583,6 +583,8 @@ namespace cryptonote
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{ {
TRY_ENTRY();
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; }; struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; };
std::vector<result> results(tx_blobs.size()); std::vector<result> results(tx_blobs.size());
@ -636,6 +638,8 @@ namespace cryptonote
MDEBUG("tx added: " << results[i].hash); MDEBUG("tx added: " << results[i].hash);
} }
return ok; return ok;
CATCH_ENTRY_L0("core::handle_incoming_txs()", false);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
@ -1062,17 +1066,20 @@ namespace cryptonote
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::cleanup_handle_incoming_blocks(bool force_sync) bool core::cleanup_handle_incoming_blocks(bool force_sync)
{ {
bool success = false;
try { try {
m_blockchain_storage.cleanup_handle_incoming_blocks(force_sync); success = m_blockchain_storage.cleanup_handle_incoming_blocks(force_sync);
} }
catch (...) {} catch (...) {}
m_incoming_tx_lock.unlock(); m_incoming_tx_lock.unlock();
return true; return success;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate) bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
{ {
TRY_ENTRY();
// load json & DNS checkpoints every 10min/hour respectively, // load json & DNS checkpoints every 10min/hour respectively,
// and verify them with respect to what blocks we already have // and verify them with respect to what blocks we already have
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints."); CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
@ -1096,6 +1103,8 @@ namespace cryptonote
if(update_miner_blocktemplate && bvc.m_added_to_main_chain) if(update_miner_blocktemplate && bvc.m_added_to_main_chain)
update_miner_block_template(); update_miner_block_template();
return true; return true;
CATCH_ENTRY_L0("core::handle_incoming_block()", false);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
// Used by the RPC server to check the size of an incoming // Used by the RPC server to check the size of an incoming

View File

@ -364,7 +364,12 @@ namespace cryptonote
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
m_core.cleanup_handle_incoming_blocks(true); if (!m_core.cleanup_handle_incoming_blocks(true))
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
m_core.resume_mine();
return 1;
}
m_core.resume_mine(); m_core.resume_mine();
if(bvc.m_verifivation_failed) if(bvc.m_verifivation_failed)
{ {
@ -623,7 +628,12 @@ namespace cryptonote
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
m_core.cleanup_handle_incoming_blocks(true); if (!m_core.cleanup_handle_incoming_blocks(true))
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
m_core.resume_mine();
return 1;
}
m_core.resume_mine(); m_core.resume_mine();
if( bvc.m_verifivation_failed ) if( bvc.m_verifivation_failed )
@ -1056,7 +1066,11 @@ skip:
})) }))
LOG_ERROR_CCONTEXT("span connection id not found"); LOG_ERROR_CCONTEXT("span connection id not found");
m_core.cleanup_handle_incoming_blocks(); if (!m_core.cleanup_handle_incoming_blocks())
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
return 1;
}
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height); m_block_queue.remove_spans(span_connection_id, start_height);
return 1; return 1;
@ -1081,7 +1095,12 @@ skip:
})) }))
LOG_ERROR_CCONTEXT("span connection id not found"); LOG_ERROR_CCONTEXT("span connection id not found");
m_core.cleanup_handle_incoming_blocks(); if (!m_core.cleanup_handle_incoming_blocks())
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
return 1;
}
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height); m_block_queue.remove_spans(span_connection_id, start_height);
return 1; return 1;
@ -1095,7 +1114,12 @@ skip:
})) }))
LOG_ERROR_CCONTEXT("span connection id not found"); LOG_ERROR_CCONTEXT("span connection id not found");
m_core.cleanup_handle_incoming_blocks(); if (!m_core.cleanup_handle_incoming_blocks())
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
return 1;
}
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height); m_block_queue.remove_spans(span_connection_id, start_height);
return 1; return 1;
@ -1108,7 +1132,11 @@ skip:
MCINFO("sync-info", "Block process time (" << blocks.size() << " blocks, " << num_txs << " txs): " << block_process_time_full + transactions_process_time_full << " (" << transactions_process_time_full << "/" << block_process_time_full << ") ms"); MCINFO("sync-info", "Block process time (" << blocks.size() << " blocks, " << num_txs << " txs): " << block_process_time_full + transactions_process_time_full << " (" << transactions_process_time_full << "/" << block_process_time_full << ") ms");
m_core.cleanup_handle_incoming_blocks(); if (!m_core.cleanup_handle_incoming_blocks())
{
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
return 1;
}
m_block_queue.remove_spans(span_connection_id, start_height); m_block_queue.remove_spans(span_connection_id, start_height);