mirror of
				https://github.com/monero-project/monero.git
				synced 2025-11-03 20:04:33 -05:00 
			
		
		
		
	Merge pull request #6545
bb4d95c blockchain: detect and log bad difficulty calculations (moneromooo-monero)
			
			
This commit is contained in:
		
						commit
						cb75003642
					
				
					 1 changed files with 72 additions and 5 deletions
				
			
		| 
						 | 
					@ -812,12 +812,20 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
 | 
				
			||||||
// less blocks than desired if there aren't enough.
 | 
					// less blocks than desired if there aren't enough.
 | 
				
			||||||
difficulty_type Blockchain::get_difficulty_for_next_block()
 | 
					difficulty_type Blockchain::get_difficulty_for_next_block()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  LOG_PRINT_L3("Blockchain::" << __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::stringstream ss;
 | 
				
			||||||
 | 
					  bool print = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int done = 0;
 | 
				
			||||||
 | 
					  ss << "get_difficulty_for_next_block: height " << m_db->height() << std::endl;
 | 
				
			||||||
  if (m_fixed_difficulty)
 | 
					  if (m_fixed_difficulty)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return m_db->height() ? m_fixed_difficulty : 1;
 | 
					    return m_db->height() ? m_fixed_difficulty : 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG_PRINT_L3("Blockchain::" << __func__);
 | 
					start:
 | 
				
			||||||
 | 
					  difficulty_type D = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  crypto::hash top_hash = get_tail_id();
 | 
					  crypto::hash top_hash = get_tail_id();
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
| 
						 | 
					@ -826,21 +834,30 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
 | 
				
			||||||
    // something a bit out of date, but that's fine since anything which
 | 
					    // 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,
 | 
					    // requires the blockchain lock will have acquired it in the first place,
 | 
				
			||||||
    // and it will be unlocked only when called from the getinfo RPC
 | 
					    // and it will be unlocked only when called from the getinfo RPC
 | 
				
			||||||
 | 
					    ss << "Locked, tail id " << top_hash << ", cached is " << m_difficulty_for_next_block_top_hash << std::endl;
 | 
				
			||||||
    if (top_hash == m_difficulty_for_next_block_top_hash)
 | 
					    if (top_hash == m_difficulty_for_next_block_top_hash)
 | 
				
			||||||
      return m_difficulty_for_next_block;
 | 
					    {
 | 
				
			||||||
 | 
					      ss << "Same, using cached diff " << m_difficulty_for_next_block << std::endl;
 | 
				
			||||||
 | 
					      D = m_difficulty_for_next_block;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
					  CRITICAL_REGION_LOCAL(m_blockchain_lock);
 | 
				
			||||||
  std::vector<uint64_t> timestamps;
 | 
					  std::vector<uint64_t> timestamps;
 | 
				
			||||||
  std::vector<difficulty_type> difficulties;
 | 
					  std::vector<difficulty_type> difficulties;
 | 
				
			||||||
  uint64_t height;
 | 
					  uint64_t height;
 | 
				
			||||||
  top_hash = get_tail_id(height); // get it again now that we have the lock
 | 
					  auto new_top_hash = get_tail_id(height); // get it again now that we have the lock
 | 
				
			||||||
  ++height; // top block height to blockchain height
 | 
					  ++height;
 | 
				
			||||||
 | 
					  if (!(new_top_hash == top_hash)) D=0;
 | 
				
			||||||
 | 
					  ss << "Re-locked, height " << height << ", tail id " << new_top_hash << (new_top_hash == top_hash ? "" : " (different)") << std::endl;
 | 
				
			||||||
 | 
					  top_hash = new_top_hash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // ND: Speedup
 | 
					  // ND: Speedup
 | 
				
			||||||
  // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
 | 
					  // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
 | 
				
			||||||
  //    then when the next block difficulty is queried, push the latest height data and
 | 
					  //    then when the next block difficulty is queried, push the latest height data and
 | 
				
			||||||
  //    pop the oldest one from the list. This only requires 1x read per height instead
 | 
					  //    pop the oldest one from the list. This only requires 1x read per height instead
 | 
				
			||||||
  //    of doing 735 (DIFFICULTY_BLOCKS_COUNT).
 | 
					  //    of doing 735 (DIFFICULTY_BLOCKS_COUNT).
 | 
				
			||||||
 | 
					  bool check = false;
 | 
				
			||||||
  if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT)
 | 
					  if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= DIFFICULTY_BLOCKS_COUNT)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    uint64_t index = height - 1;
 | 
					    uint64_t index = height - 1;
 | 
				
			||||||
| 
						 | 
					@ -855,8 +872,12 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
 | 
				
			||||||
    m_timestamps_and_difficulties_height = height;
 | 
					    m_timestamps_and_difficulties_height = height;
 | 
				
			||||||
    timestamps = m_timestamps;
 | 
					    timestamps = m_timestamps;
 | 
				
			||||||
    difficulties = m_difficulties;
 | 
					    difficulties = m_difficulties;
 | 
				
			||||||
 | 
					    check = true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  //else
 | 
				
			||||||
 | 
					  std::vector<uint64_t> timestamps_from_cache = timestamps;
 | 
				
			||||||
 | 
					  std::vector<difficulty_type> difficulties_from_cache = difficulties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT));
 | 
					    uint64_t offset = height - std::min <uint64_t> (height, static_cast<uint64_t>(DIFFICULTY_BLOCKS_COUNT));
 | 
				
			||||||
    if (offset == 0)
 | 
					    if (offset == 0)
 | 
				
			||||||
| 
						 | 
					@ -869,22 +890,68 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
 | 
				
			||||||
      timestamps.reserve(height - offset);
 | 
					      timestamps.reserve(height - offset);
 | 
				
			||||||
      difficulties.reserve(height - offset);
 | 
					      difficulties.reserve(height - offset);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    ss << "Looking up " << (height - offset) << " from " << offset << std::endl;
 | 
				
			||||||
    for (; offset < height; offset++)
 | 
					    for (; offset < height; offset++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      timestamps.push_back(m_db->get_block_timestamp(offset));
 | 
					      timestamps.push_back(m_db->get_block_timestamp(offset));
 | 
				
			||||||
      difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
 | 
					      difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (check) if (timestamps != timestamps_from_cache || difficulties !=difficulties_from_cache)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ss << "Inconsistency XXX:" << std::endl;
 | 
				
			||||||
 | 
					      ss << "top hash: "<<top_hash << std::endl;
 | 
				
			||||||
 | 
					      ss << "timestamps: " << timestamps_from_cache.size() << " from cache, but " << timestamps.size() << " without" << std::endl;
 | 
				
			||||||
 | 
					      ss << "difficulties: " << difficulties_from_cache.size() << " from cache, but " << difficulties.size() << " without" << std::endl;
 | 
				
			||||||
 | 
					      ss << "timestamps_from_cache:" << std::endl; for (const auto &v :timestamps_from_cache) ss << "  " << v << std::endl;
 | 
				
			||||||
 | 
					      ss << "timestamps:" << std::endl; for (const auto &v :timestamps) ss << "  " << v << std::endl;
 | 
				
			||||||
 | 
					      ss << "difficulties_from_cache:" << std::endl; for (const auto &v :difficulties_from_cache) ss << "  " << v << std::endl;
 | 
				
			||||||
 | 
					      ss << "difficulties:" << std::endl; for (const auto &v :difficulties) ss << "  " << v << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      uint64_t dbh = m_db->height();
 | 
				
			||||||
 | 
					      uint64_t sh = dbh < 10000 ? 0 : dbh - 10000;
 | 
				
			||||||
 | 
					      ss << "History from -10k at :" << dbh << ", from " << sh << std::endl;
 | 
				
			||||||
 | 
					      for (uint64_t h = sh; h < dbh; ++h)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        uint64_t ts = m_db->get_block_timestamp(h);
 | 
				
			||||||
 | 
					        difficulty_type d = m_db->get_block_cumulative_difficulty(h);
 | 
				
			||||||
 | 
					        ss << "  " << h << " " << ts << " " << d << std::endl;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      print = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    m_timestamps_and_difficulties_height = height;
 | 
					    m_timestamps_and_difficulties_height = height;
 | 
				
			||||||
    m_timestamps = timestamps;
 | 
					    m_timestamps = timestamps;
 | 
				
			||||||
    m_difficulties = difficulties;
 | 
					    m_difficulties = difficulties;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t target = get_difficulty_target();
 | 
					  size_t target = get_difficulty_target();
 | 
				
			||||||
  difficulty_type diff = next_difficulty(timestamps, difficulties, target);
 | 
					  difficulty_type diff = next_difficulty(timestamps, difficulties, target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CRITICAL_REGION_LOCAL1(m_difficulty_lock);
 | 
					  CRITICAL_REGION_LOCAL1(m_difficulty_lock);
 | 
				
			||||||
  m_difficulty_for_next_block_top_hash = top_hash;
 | 
					  m_difficulty_for_next_block_top_hash = top_hash;
 | 
				
			||||||
  m_difficulty_for_next_block = diff;
 | 
					  m_difficulty_for_next_block = diff;
 | 
				
			||||||
 | 
					  if (D && D != diff)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    ss << "XXX Mismatch at " << height << "/" << top_hash << "/" << get_tail_id() << ": cached " << D << ", real " << diff << std::endl;
 | 
				
			||||||
 | 
					    print = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ++done;
 | 
				
			||||||
 | 
					  if (done == 1 && D && D != diff)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    print = true;
 | 
				
			||||||
 | 
					    ss << "Might be a race. Let's see what happens if we try again..." << std::endl;
 | 
				
			||||||
 | 
					    epee::misc_utils::sleep_no_w(100);
 | 
				
			||||||
 | 
					    goto start;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ss << "Diff for " << top_hash << ": " << diff << std::endl;
 | 
				
			||||||
 | 
					  if (print)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    MGINFO("START DUMP");
 | 
				
			||||||
 | 
					    MGINFO(ss.str());
 | 
				
			||||||
 | 
					    MGINFO("END DUMP");
 | 
				
			||||||
 | 
					    MGINFO("Please send moneromooo on Freenode the contents of this log, from a couple dozen lines before START DUMP to END DUMP");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return diff;
 | 
					  return diff;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
//------------------------------------------------------------------
 | 
					//------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue