diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 63bee8a0..ad7b4ea4 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3838,7 +3838,14 @@ bool blockchain_storage::find_blockchain_supplement(const std::list mis; get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis); CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, block " << get_block_hash(m_db_blocks[i]->bl) << " [" << i << "] contains missing transactions: " << mis); - blocks.back().third = m_db_transactions.find(get_coinbase_hash_cached(*m_db_blocks[i])); + //blocks.back().third = m_db_transactions.find(get_coinbase_hash_cached(*m_db_blocks[i])); + + crypto::hash coinbase_hash = get_coinbase_hash_cached(*m_db_blocks[i]); + blocks.back().third = m_db_transactions.find(coinbase_hash); + if (!blocks.back().third) + { + LOG_PRINT_YELLOW("m_db_transactions.find failed for coinbase hash: " << coinbase_hash << ", height: " << i, LOG_LEVEL_0); + } } return true; } diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index efeb2759..891c314d 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -77,6 +77,28 @@ namespace currency // This is an optional data fields, It is not included in serialization and therefore is never stored in the database. // It might be calculated "on the fly" to speed up access operations. mutable std::shared_ptr m_cache_coinbase_id; + mutable std::atomic m_cache_coinbase_state{0}; + + block_extended_info& operator=(const block_extended_info& rhs) + { + this->bl = rhs.bl; + this->height = rhs.height; + this->block_cumulative_size = rhs.block_cumulative_size; + this->cumulative_diff_adjusted = rhs.cumulative_diff_adjusted; + this->cumulative_diff_precise = rhs.cumulative_diff_precise; + this->cumulative_diff_precise_adjusted = rhs.cumulative_diff_precise_adjusted; + this->difficulty = rhs.difficulty; + this->already_generated_coins = rhs.already_generated_coins; + this->stake_hash = rhs.stake_hash; + this->version = rhs.version; + this->this_block_tx_fee_median = rhs.this_block_tx_fee_median; + this->effective_tx_fee_median = rhs.effective_tx_fee_median; + this->m_cache_coinbase_id.reset(); + this->m_cache_coinbase_state = 0; + return *this; + } + block_extended_info(const block_extended_info& rhs) { *this = rhs; } + block_extended_info() = default; }; struct gindex_increment @@ -194,14 +216,31 @@ namespace currency inline crypto::hash get_coinbase_hash_cached(const block_extended_info& bei) - { - std::shared_ptr local_coinbase_id = bei.m_cache_coinbase_id; - if (!local_coinbase_id) - { - bei.m_cache_coinbase_id = std::make_shared(get_transaction_hash(bei.bl.miner_tx)); - local_coinbase_id = bei.m_cache_coinbase_id; - } - return *local_coinbase_id; + { + // bei.m_cache_coinbase_state : 0 -- m_cache_coinbase_id is empty + // 1 -- m_cache_coinbase_id is calculating and writing + // 2 -- m_cache_coinbase_id is ready to read + if (bei.m_cache_coinbase_state == 2) + { + // state is 2, cache must be ready, access the cache + std::shared_ptr local_coinbase_id = bei.m_cache_coinbase_id; + CHECK_AND_ASSERT_THROW_MES(local_coinbase_id, "internal error: m_cache_coinbase_id is empty"); + return *local_coinbase_id; + } + + uint8_t state = 0; + if (bei.m_cache_coinbase_state.compare_exchange_strong(state, 1)) + { + // state has just been 0, now 1, we're calculating + std::shared_ptr ptr_h = std::make_shared(get_transaction_hash(bei.bl.miner_tx)); + bei.m_cache_coinbase_id = ptr_h; + bei.m_cache_coinbase_state = 2; + return *ptr_h; + } + + // state is 1, another thread is calculating, so we calculate locally and don't touch the cache + crypto::hash h = get_transaction_hash(bei.bl.miner_tx); + return h; } } // namespace currency