From 0622741c03a118558cf394f73493b3f935b53334 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Mon, 18 Feb 2019 15:43:08 +0000 Subject: [PATCH] blockchain: fix block template creation race If two create_block_template are called at nearly the same time, and a block is added at nearly the same time, this could happen: - the blockchain top block is B0 - thread 1 enters create_block_template, takes blockchain lock - thread 1 creates a fresh block referencing prev block B0 - thread 1 releases blockchain lock - thread 0 adds a new block - thread 0 enters create_block_template - thread 0 updates block template - thread 1 takes txpool lock and continues creating block template - thread 1 overwrites block template with previous data --- src/cryptonote_core/blockchain.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 1a533822f..7462189f4 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1264,7 +1264,10 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m uint64_t already_generated_coins; uint64_t pool_cookie; - CRITICAL_REGION_BEGIN(m_blockchain_lock); + m_tx_pool.lock(); + const auto txpool_unlocker = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); }); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + height = m_db->height(); if (m_btc_valid) { // The pool cookie is atomic. The lack of locking is OK, as if it changes @@ -1300,8 +1303,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m median_weight = m_current_block_cumul_weight_limit / 2; already_generated_coins = m_db->get_block_already_generated_coins(height - 1); - CRITICAL_REGION_END(); - size_t txs_weight; uint64_t fee; if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version())) @@ -1312,7 +1313,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) size_t real_txs_weight = 0; uint64_t real_fee = 0; - CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock); for(crypto::hash &cur_hash: b.tx_hashes) { auto cur_res = m_tx_pool.m_transactions.find(cur_hash); @@ -1356,7 +1356,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m { LOG_ERROR("Creating block template: error: wrongly calculated fee"); } - CRITICAL_REGION_END(); + MDEBUG("Creating block template: height " << height << ", median weight " << median_weight << ", already generated coins " << already_generated_coins <<