Remove "valid" from RPC work_validate if difficulty is not explicit (#2689)

This is a semantics change for RPC `work_validate`, due to the transition to new work levels with epoch 2.

Two new fields are added:
- `valid_all` , true if the work is valid at the **current default difficulty** (updated to epoch_2 levels after the first epoch_2 block is processed)
- `valid_receive` , true if the work is valid at the lower epoch_2 receive difficulty

If difficulty is not explicitly given, then the `valid` field is not included in the response, to break integrations loudly.
This commit is contained in:
Guilherme Lawless 2020-04-09 10:54:53 +01:00 committed by GitHub
commit 41ce708a55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 13 deletions

View file

@ -5117,8 +5117,21 @@ void nano::json_handler::work_validate ()
multiplier_optional_impl (work_version, difficulty);
if (!ec)
{
/* Transition to epoch_2 difficulty levels breaks previous behavior.
* When difficulty is not given, the default difficulty to validate changes when the first epoch_2 block is seen, breaking previous behavior.
* For this reason, when difficulty is not given, the "valid" field is no longer included in the response to break loudly any client expecting it.
* Instead, use the new fields:
* * valid_all: the work is valid at the current highest difficulty threshold
* * valid_receive: the work is valid for a receive block in an epoch_2 upgraded account
*/
auto result_difficulty (nano::work_difficulty (work_version, hash, work));
response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0");
if (request.count ("difficulty"))
{
response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0");
}
response_l.put ("valid_all", (result_difficulty >= node.default_difficulty (work_version)) ? "1" : "0");
response_l.put ("valid_receive", (result_difficulty >= nano::work_threshold (work_version, nano::block_details (nano::epoch::epoch_2, false, true, false))) ? "1" : "0");
response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.default_difficulty (work_version));
response_l.put ("multiplier", nano::to_string (result_multiplier));

View file

@ -4029,8 +4029,9 @@ TEST (rpc, work_validate)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
std::string validate_text (response.json.get<std::string> ("valid"));
ASSERT_EQ ("1", validate_text);
ASSERT_EQ (0, response.json.count ("valid"));
ASSERT_TRUE (response.json.get<bool> ("valid_all"));
ASSERT_TRUE (response.json.get<bool> ("valid_receive"));
std::string difficulty_text (response.json.get<std::string> ("difficulty"));
uint64_t difficulty;
ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty));
@ -4048,8 +4049,9 @@ TEST (rpc, work_validate)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
std::string validate_text (response.json.get<std::string> ("valid"));
ASSERT_EQ ("0", validate_text);
ASSERT_EQ (0, response.json.count ("valid"));
ASSERT_FALSE (response.json.get<bool> ("valid_all"));
ASSERT_FALSE (response.json.get<bool> ("valid_receive"));
std::string difficulty_text (response.json.get<std::string> ("difficulty"));
uint64_t difficulty;
ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty));
@ -4069,8 +4071,9 @@ TEST (rpc, work_validate)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
bool validate (response.json.get<bool> ("valid"));
ASSERT_TRUE (validate);
ASSERT_TRUE (response.json.get<bool> ("valid"));
ASSERT_TRUE (response.json.get<bool> ("valid_all"));
ASSERT_TRUE (response.json.get<bool> ("valid_receive"));
}
uint64_t difficulty4 (0xfff0000000000000);
request.put ("work", nano::to_string_hex (work1));
@ -4083,8 +4086,9 @@ TEST (rpc, work_validate)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
bool validate (response.json.get<bool> ("valid"));
ASSERT_EQ (result_difficulty >= difficulty4, validate);
ASSERT_EQ (result_difficulty >= difficulty4, response.json.get<bool> ("valid"));
ASSERT_EQ (result_difficulty >= node1.default_difficulty (nano::work_version::work_1), response.json.get<bool> ("valid_all"));
ASSERT_EQ (result_difficulty >= node1.network_params.network.publish_thresholds.epoch_2_receive, response.json.get<bool> ("valid_all"));
}
uint64_t work3 (*node1.work_generate_blocking (hash, difficulty4));
request.put ("work", nano::to_string_hex (work3));
@ -4096,8 +4100,9 @@ TEST (rpc, work_validate)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
bool validate (response.json.get<bool> ("valid"));
ASSERT_TRUE (validate);
ASSERT_TRUE (response.json.get<bool> ("valid"));
ASSERT_TRUE (response.json.get<bool> ("valid_all"));
ASSERT_TRUE (response.json.get<bool> ("valid_receive"));
}
}
@ -4129,7 +4134,9 @@ TEST (rpc, work_validate_epoch_2)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
ASSERT_TRUE (response.json.get<bool> ("valid"));
ASSERT_EQ (0, response.json.count ("valid"));
ASSERT_TRUE (response.json.get<bool> ("valid_all"));
ASSERT_TRUE (response.json.get<bool> ("valid_receive"));
std::string difficulty_text (response.json.get<std::string> ("difficulty"));
uint64_t difficulty{ 0 };
ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty));
@ -4148,7 +4155,9 @@ TEST (rpc, work_validate_epoch_2)
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
ASSERT_FALSE (response.json.get<bool> ("valid"));
ASSERT_EQ (0, response.json.count ("valid"));
ASSERT_FALSE (response.json.get<bool> ("valid_all"));
ASSERT_TRUE (response.json.get<bool> ("valid_receive"));
std::string difficulty_text (response.json.get<std::string> ("difficulty"));
uint64_t difficulty{ 0 };
ASSERT_FALSE (nano::from_string_hex (difficulty_text, difficulty));