Work multiplier format and RPC work_validate fix for lower difficulties (#1984)

* Format multipliers using fixed and max precision rather than scientific

* Fix RPC work_validate returning invalid for difficulty lower than threshold

* Move nano::to/from_string_hex to lib/numbers.hpp

* Parameter can be const in nano::to_string_hex

* Extract nano::to_string method for converting double with fixed and custom precision. Use std streams rather than boost

* Fix intermitent failure of rpc.work_generate test

* Prevent crash in debug if given difficulty is 0
This commit is contained in:
Guilherme Lawless 2019-05-15 11:57:20 +01:00 committed by cryptocode
commit e822707d90
7 changed files with 62 additions and 47 deletions

View file

@ -16,43 +16,6 @@ bool blocks_equal (T const & first, nano::block const & second)
}
}
std::string nano::to_string_hex (uint64_t value_a)
{
std::stringstream stream;
stream << std::hex << std::noshowbase << std::setw (16) << std::setfill ('0');
stream << value_a;
return stream.str ();
}
bool nano::from_string_hex (std::string const & value_a, uint64_t & target_a)
{
auto error (value_a.empty ());
if (!error)
{
error = value_a.size () > 16;
if (!error)
{
std::stringstream stream (value_a);
stream << std::hex << std::noshowbase;
try
{
uint64_t number_l;
stream >> number_l;
target_a = number_l;
if (!stream.eof ())
{
error = true;
}
}
catch (std::runtime_error &)
{
error = true;
}
}
}
return error;
}
std::string nano::block::to_json () const
{
std::string result;

View file

@ -12,8 +12,6 @@
namespace nano
{
std::string to_string_hex (uint64_t);
bool from_string_hex (std::string const &, uint64_t &);
// We operate on streams of uint8_t by convention
using stream = std::basic_streambuf<uint8_t>;
// Read a raw byte stream the size of `T' and fill value.

View file

@ -774,6 +774,51 @@ std::string nano::uint128_union::to_string_dec () const
return result;
}
std::string nano::to_string_hex (uint64_t const value_a)
{
std::stringstream stream;
stream << std::hex << std::noshowbase << std::setw (16) << std::setfill ('0');
stream << value_a;
return stream.str ();
}
bool nano::from_string_hex (std::string const & value_a, uint64_t & target_a)
{
auto error (value_a.empty ());
if (!error)
{
error = value_a.size () > 16;
if (!error)
{
std::stringstream stream (value_a);
stream << std::hex << std::noshowbase;
try
{
uint64_t number_l;
stream >> number_l;
target_a = number_l;
if (!stream.eof ())
{
error = true;
}
}
catch (std::runtime_error &)
{
error = true;
}
}
}
return error;
}
std::string nano::to_string (double const value_a, int const precision_a)
{
std::stringstream stream;
stream << std::setprecision (precision_a) << std::fixed;
stream << value_a;
return stream.str ();
}
uint64_t nano::difficulty::from_multiplier (double const multiplier_a, uint64_t const base_difficulty_a)
{
assert (multiplier_a > 0.);

View file

@ -127,6 +127,16 @@ bool validate_message_batch (const unsigned char **, size_t *, const unsigned ch
void deterministic_key (nano::uint256_union const &, uint32_t, nano::uint256_union &);
nano::public_key pub_key (nano::private_key const &);
/* Conversion methods */
std::string to_string_hex (uint64_t const);
bool from_string_hex (std::string const &, uint64_t &);
/**
* Convert a double to string in fixed format
* @param precision_a (optional) use a specific precision (default is the maximum)
*/
std::string to_string (double const, int const precision_a = std::numeric_limits<double>::digits10);
namespace difficulty
{
uint64_t from_multiplier (double const, uint64_t const);

View file

@ -115,7 +115,7 @@ void nano::work_pool::loop (uint64_t thread)
{
// If the ticket matches what we started with, we're the ones that found the solution
assert (output >= current_l.difficulty);
assert (work_value (current_l.item, work) == output);
assert (current_l.difficulty == 0 || work_value (current_l.item, work) == output);
// Signal other threads to stop their work next time they check ticket
++ticket;
pending.pop_front ();

View file

@ -839,7 +839,7 @@ void nano::json_handler::active_difficulty ()
auto difficulty_active = node.active.active_difficulty ();
response_l.put ("difficulty_active", nano::to_string_hex (difficulty_active));
auto multiplier = nano::difficulty::to_multiplier (difficulty_active, node.network_params.network.publish_threshold);
response_l.put ("multiplier", std::to_string (multiplier));
response_l.put ("multiplier", nano::to_string (multiplier));
response_errors ();
}
@ -4363,7 +4363,7 @@ void nano::json_handler::work_generate ()
nano::work_validate (hash, work_a.value (), &result_difficulty);
response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
auto multiplier = nano::difficulty::to_multiplier (result_difficulty, this->node.network_params.network.publish_threshold);
response_l.put ("multiplier", multiplier);
response_l.put ("multiplier", nano::to_string (multiplier));
boost::property_tree::write_json (ostream, response_l);
rpc_l->response (ostream.str ());
}
@ -4451,12 +4451,11 @@ void nano::json_handler::work_validate ()
if (!ec)
{
uint64_t result_difficulty (0);
bool invalid (nano::work_validate (hash, work, &result_difficulty));
bool valid (!invalid && result_difficulty >= difficulty);
response_l.put ("valid", valid ? "1" : "0");
nano::work_validate (hash, work, &result_difficulty);
response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0");
response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
auto multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold);
response_l.put ("multiplier", multiplier);
response_l.put ("multiplier", nano::to_string (multiplier));
}
response_errors ();
}

View file

@ -2462,7 +2462,7 @@ TEST (rpc, work_generate)
ASSERT_FALSE (nano::from_string_hex (response_difficulty_text, response_difficulty));
ASSERT_EQ (result_difficulty, response_difficulty);
auto multiplier = response.json.get<double> ("multiplier");
ASSERT_EQ (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_threshold), multiplier);
ASSERT_NEAR (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_threshold), multiplier, 1e-6);
}
TEST (rpc, work_generate_difficulty)