diff --git a/nano/core_test/difficulty.cpp b/nano/core_test/difficulty.cpp index 2ba37917..52521dcb 100644 --- a/nano/core_test/difficulty.cpp +++ b/nano/core_test/difficulty.cpp @@ -26,6 +26,24 @@ TEST (difficulty, multipliers) ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (expected_multiplier, base)); } + { + uint64_t base = std::numeric_limits::max (); + uint64_t difficulty = 0xffffffffffffff00; + double expected_multiplier = 0.00390625; + + ASSERT_NEAR (expected_multiplier, nano::difficulty::to_multiplier (difficulty, base), 1e-10); + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (expected_multiplier, base)); + } + + { + uint64_t base = 0x8000000000000000; + uint64_t difficulty = 0xf000000000000000; + double expected_multiplier = 8.0; + + ASSERT_NEAR (expected_multiplier, nano::difficulty::to_multiplier (difficulty, base), 1e-10); + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (expected_multiplier, base)); + } + { #ifndef NDEBUG // Causes valgrind to be noisy @@ -46,3 +64,44 @@ TEST (difficulty, network_constants) { ASSERT_NEAR (16., nano::difficulty::to_multiplier (nano::network_constants::publish_full_threshold, nano::network_constants::publish_beta_threshold), 1e-10); } + +TEST (difficulty, overflow) +{ + // Overflow max (attempt to overflow & receive lower difficulty) + { + uint64_t base = std::numeric_limits::max (); // Max possible difficulty + uint64_t difficulty = std::numeric_limits::max (); + double multiplier = 1.001; // Try to increase difficulty above max + + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (multiplier, base)); + } + + // Overflow min (attempt to overflow & receive higher difficulty) + { + uint64_t base = 1; // Min possible difficulty before 0 + uint64_t difficulty = 0; + double multiplier = 0.999; // Decrease difficulty + + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (multiplier, base)); + } +} + +TEST (difficulty, zero) +{ + // Tests with base difficulty 0 should return 0 with any multiplier + { + uint64_t base = 0; // Min possible difficulty + uint64_t difficulty = 0; + double multiplier = 0.000000001; // Decrease difficulty + + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (multiplier, base)); + } + + { + uint64_t base = 0; // Min possible difficulty + uint64_t difficulty = 0; + double multiplier = 1000000000.0; // Increase difficulty + + ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (multiplier, base)); + } +} diff --git a/nano/lib/numbers.cpp b/nano/lib/numbers.cpp index a8f36ba8..17306134 100644 --- a/nano/lib/numbers.cpp +++ b/nano/lib/numbers.cpp @@ -823,7 +823,8 @@ std::string nano::to_string (double const value_a, int const precision_a) uint64_t nano::difficulty::from_multiplier (double const multiplier_a, uint64_t const base_difficulty_a) { assert (multiplier_a > 0.); - return (-static_cast ((-base_difficulty_a) / multiplier_a)); + uint64_t reverse_difficulty (static_cast ((-base_difficulty_a) / multiplier_a)); + return (reverse_difficulty != 0 || base_difficulty_a == 0 || multiplier_a < 1. ? -reverse_difficulty : std::numeric_limits::max ()); } double nano::difficulty::to_multiplier (uint64_t const difficulty_a, uint64_t const base_difficulty_a)