blockchain: cache difficulty for next block

Takes about 10 ms, which takes pretty much all of the get_info
RPC, which is called pretty often from wallets.

Also add a new lock so we don't need to lock the blockchain lock,
which will avoid blocking for a long time when calling the getinfo
RPC while syncing. Users of get_difficulty_for_next_block who need
the lock will have locked it already.
This commit is contained in:
moneromooo-monero 2018-03-17 10:15:33 +00:00
parent 5710edf040
commit a6a54fa883
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
2 changed files with 22 additions and 3 deletions

View file

@ -156,7 +156,9 @@ static const struct {
//------------------------------------------------------------------ //------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) : Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0), m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0),
m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false) m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false),
m_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
} }
@ -751,7 +753,17 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
difficulty_type Blockchain::get_difficulty_for_next_block() difficulty_type Blockchain::get_difficulty_for_next_block()
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
CRITICAL_REGION_LOCAL(m_difficulty_lock);
// we can call this without the blockchain lock, it might just give us
// something a bit out of date, but that's fine since anything which
// requires the blockchain lock will have acquired it in the first place,
// and it will be unlocked only when called from the getinfo RPC
crypto::hash top_hash = get_tail_id();
if (top_hash == m_difficulty_for_next_block_top_hash)
return m_difficulty_for_next_block;
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties; std::vector<difficulty_type> difficulties;
auto height = m_db->height(); auto height = m_db->height();
@ -794,7 +806,10 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
m_difficulties = difficulties; m_difficulties = difficulties;
} }
size_t target = get_difficulty_target(); size_t target = get_difficulty_target();
return next_difficulty(timestamps, difficulties, target); difficulty_type diff = next_difficulty(timestamps, difficulties, target);
m_difficulty_for_next_block_top_hash = top_hash;
m_difficulty_for_next_block = diff;
return diff;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
// This function removes blocks from the blockchain until it gets to the // This function removes blocks from the blockchain until it gets to the

View file

@ -1006,6 +1006,10 @@ namespace cryptonote
std::vector<difficulty_type> m_difficulties; std::vector<difficulty_type> m_difficulties;
uint64_t m_timestamps_and_difficulties_height; uint64_t m_timestamps_and_difficulties_height;
epee::critical_section m_difficulty_lock;
crypto::hash m_difficulty_for_next_block_top_hash;
difficulty_type m_difficulty_for_next_block;
boost::asio::io_service m_async_service; boost::asio::io_service m_async_service;
boost::thread_group m_async_pool; boost::thread_group m_async_pool;
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle; std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;