Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block difficulty and work validation cleanup #2601

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions nano/core_test/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,8 @@ TEST (active_transactions, prioritize_chains)
auto send5 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 20 * nano::xrb_ratio, key2.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ())));
auto send6 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send5->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 30 * nano::xrb_ratio, key3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send5->hash ())));
auto open2 (std::make_shared<nano::state_block> (key2.pub, 0, key2.pub, 10 * nano::xrb_ratio, send5->hash (), key2.prv, key2.pub, *system.work.generate (key2.pub, nano::difficulty::from_multiplier (50., node1.network_params.network.publish_threshold))));
uint64_t difficulty1 (0);
nano::work_validate (*open2, &difficulty1);
uint64_t difficulty2 (0);
nano::work_validate (*send6, &difficulty2);
auto difficulty1 (open2->difficulty ());
auto difficulty2 (send6->difficulty ());

node1.process_active (send1);
node1.process_active (open1);
Expand Down Expand Up @@ -517,11 +515,9 @@ TEST (active_transactions, update_difficulty)
nano::keypair key1;
// Generate blocks & start elections
auto send1 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - 100, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (genesis.hash ())));
uint64_t difficulty1 (0);
nano::work_validate (*send1, &difficulty1);
auto difficulty1 (send1->difficulty ());
auto send2 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send1->hash (), nano::test_genesis_key.pub, nano::genesis_amount - 200, key1.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send1->hash ())));
uint64_t difficulty2 (0);
nano::work_validate (*send2, &difficulty2);
auto difficulty2 (send2->difficulty ());
node1.process_active (send1);
node1.process_active (send2);
node1.block_processor.flush ();
Expand Down
6 changes: 6 additions & 0 deletions nano/core_test/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ TEST (block, publish_req_serialization)
ASSERT_EQ (*req.block, *req2.block);
}

TEST (block, difficulty)
{
nano::send_block block (0, 1, 2, nano::keypair ().prv, 4, 5);
ASSERT_EQ (block.difficulty (), nano::work_difficulty (block.work_version (), block.root (), block.block_work ()));
}

TEST (state_block, serialization)
{
nano::keypair key1;
Expand Down
10 changes: 3 additions & 7 deletions nano/core_test/conflicts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ TEST (conflicts, reprioritize)
nano::keypair key1;
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.work_generate_blocking (*send1);
uint64_t difficulty1;
nano::work_validate (*send1, &difficulty1);
auto difficulty1 (send1->difficulty ());
nano::send_block send1_copy (*send1);
node1.process_active (send1);
node1.block_processor.flush ();
Expand All @@ -177,8 +176,7 @@ TEST (conflicts, reprioritize)
ASSERT_EQ (difficulty1, existing1->difficulty);
}
node1.work_generate_blocking (send1_copy, difficulty1);
uint64_t difficulty2;
nano::work_validate (send1_copy, &difficulty2);
auto difficulty2 (send1_copy.difficulty ());
node1.process_active (std::make_shared<nano::send_block> (send1_copy));
node1.block_processor.flush ();
{
Expand Down Expand Up @@ -277,9 +275,7 @@ TEST (conflicts, adjusted_difficulty)
// Independent elections can have higher difficulty than adjusted tree
nano::keypair key4;
auto open_epoch2 (std::make_shared<nano::state_block> (key4.pub, 0, 0, 0, node1.ledger.epoch_link (nano::epoch::epoch_1), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key4.pub, adjusted_difficulties.find (send1->hash ())->second)));
uint64_t difficulty;
ASSERT_FALSE (nano::work_validate (*open_epoch2, &difficulty));
ASSERT_GT (difficulty, adjusted_difficulties.find (send1->hash ())->second);
ASSERT_GT (open_epoch2->difficulty (), adjusted_difficulties.find (send1->hash ())->second);
node1.process_active (open_epoch2);
node1.block_processor.flush ();
system.deadline_set (3s);
Expand Down
5 changes: 2 additions & 3 deletions nano/core_test/fakes/work_peer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,12 @@ class work_peer_connection : public std::enable_shared_from_this<work_peer_conne
auto this_l (shared_from_this ());
work_pool.generate (version, hash, [this_l, hash](boost::optional<uint64_t> work_a) {
auto result = work_a.value_or (0);
uint64_t difficulty;
nano::work_validate (this_l->version, hash, result, &difficulty);
auto difficulty (nano::work_difficulty (this_l->version, hash, result));
static nano::network_params params;
ptree::ptree message_l;
message_l.put ("work", nano::to_string_hex (result));
message_l.put ("difficulty", nano::to_string_hex (difficulty));
message_l.put ("multiplier", nano::to_string (nano::difficulty::to_multiplier (difficulty, params.network.publish_threshold)));
message_l.put ("multiplier", nano::to_string (nano::difficulty::to_multiplier (difficulty, nano::work_threshold (this_l->version))));
message_l.put ("hash", hash.to_string ());
std::stringstream ostream;
ptree::write_json (ostream, message_l);
Expand Down
6 changes: 1 addition & 5 deletions nano/core_test/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3624,9 +3624,7 @@ TEST (active_difficulty, recalculate_work)
ASSERT_EQ (node1.network_params.network.publish_threshold, node1.active.active_difficulty ());
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.work_generate_blocking (*send1);
uint64_t difficulty1;
nano::work_validate (*send1, &difficulty1);
auto multiplier1 = nano::difficulty::to_multiplier (difficulty1, node1.network_params.network.publish_threshold);
auto multiplier1 = nano::difficulty::to_multiplier (send1->difficulty (), nano::work_threshold (send1->work_version ()));
// Process as local block
node1.process_active (send1);
system.deadline_set (2s);
Expand All @@ -3643,8 +3641,6 @@ TEST (active_difficulty, recalculate_work)
node1.active.multipliers_cb.push_back (multiplier1 * (1 + i / 100.));
}
node1.work_generate_blocking (*send1);
uint64_t difficulty2;
nano::work_validate (*send1, &difficulty2);
node1.process_active (send1);
node1.active.update_active_difficulty (lock);
sum = std::accumulate (node1.active.multipliers_cb.begin (), node1.active.multipliers_cb.end (), double(0));
Expand Down
14 changes: 5 additions & 9 deletions nano/core_test/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,11 +1134,9 @@ TEST (wallet, work_watcher_update)
wallet.insert_adhoc (nano::test_genesis_key.prv);
nano::keypair key;
auto const block1 (wallet.send_action (nano::test_genesis_key.pub, key.pub, 100));
uint64_t difficulty1 (0);
nano::work_validate (*block1, &difficulty1);
auto difficulty1 (block1->difficulty ());
auto const block2 (wallet.send_action (nano::test_genesis_key.pub, key.pub, 200));
uint64_t difficulty2 (0);
nano::work_validate (*block2, &difficulty2);
auto difficulty2 (block2->difficulty ());
auto multiplier = nano::difficulty::to_multiplier (std::max (difficulty1, difficulty2), node.network_params.network.publish_threshold);
uint64_t updated_difficulty1{ difficulty1 }, updated_difficulty2{ difficulty2 };
{
Expand Down Expand Up @@ -1188,12 +1186,11 @@ TEST (wallet, work_watcher_generation_disabled)
nano::genesis genesis;
nano::keypair key;
auto block (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, genesis.hash (), nano::test_genesis_key.pub, nano::genesis_amount - nano::Mxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *pool.generate (genesis.hash ())));
uint64_t difficulty (0);
ASSERT_FALSE (nano::work_validate (*block, &difficulty));
auto difficulty (block->difficulty ());
node.wallets.watcher->add (block);
ASSERT_FALSE (node.process_local (block).code != nano::process_result::progress);
ASSERT_TRUE (node.wallets.watcher->is_watched (block->qualified_root ()));
auto multiplier = nano::difficulty::to_multiplier (difficulty, node.network_params.network.publish_threshold);
auto multiplier = nano::difficulty::to_multiplier (difficulty, nano::work_threshold (block->work_version ()));
uint64_t updated_difficulty{ difficulty };
{
nano::unique_lock<std::mutex> lock (node.active.mutex);
Expand Down Expand Up @@ -1254,8 +1251,7 @@ TEST (wallet, work_watcher_cancel)
nano::keypair key;
auto work1 (node.work_generate_blocking (nano::test_genesis_key.pub));
auto const block1 (wallet.send_action (nano::test_genesis_key.pub, key.pub, 100, *work1, false));
uint64_t difficulty1 (0);
nano::work_validate (*block1, &difficulty1);
auto difficulty1 (block1->difficulty ());
{
nano::unique_lock<std::mutex> lock (node.active.mutex);
// Prevent active difficulty repopulating multipliers
Expand Down
39 changes: 16 additions & 23 deletions nano/core_test/work_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ TEST (work, one)
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
nano::change_block block (1, 1, nano::keypair ().prv, 3, 4);
block.block_work_set (*pool.generate (block.root ()));
uint64_t difficulty;
ASSERT_FALSE (nano::work_validate (block, &difficulty));
ASSERT_LT (network_constants.publish_threshold, difficulty);
ASSERT_LT (nano::work_threshold (block.work_version ()), block.difficulty ());
}

TEST (work, disabled)
Expand All @@ -38,12 +36,9 @@ TEST (work, validate)
nano::network_constants network_constants;
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
nano::send_block send_block (1, 1, 2, nano::keypair ().prv, 4, 6);
uint64_t difficulty;
ASSERT_TRUE (nano::work_validate (send_block, &difficulty));
ASSERT_LT (difficulty, network_constants.publish_threshold);
ASSERT_LT (send_block.difficulty (), nano::work_threshold (send_block.work_version ()));
send_block.block_work_set (*pool.generate (send_block.root ()));
ASSERT_FALSE (nano::work_validate (send_block, &difficulty));
ASSERT_LT (network_constants.publish_threshold, difficulty);
ASSERT_LT (nano::work_threshold (send_block.work_version ()), send_block.difficulty ());
}

TEST (work, cancel)
Expand Down Expand Up @@ -107,9 +102,7 @@ TEST (work, opencl)
{
nano::random_pool::generate_block (root.bytes.data (), root.bytes.size ());
auto result (*pool.generate (nano::work_version::work_1, root, difficulty));
uint64_t result_difficulty (0);
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, root, result, &result_difficulty));
ASSERT_GE (result_difficulty, difficulty);
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, root, result), difficulty);
difficulty += difficulty_add;
}
}
Expand Down Expand Up @@ -146,20 +139,20 @@ TEST (work, difficulty)
uint64_t difficulty1 (0xff00000000000000);
uint64_t difficulty2 (0xfff0000000000000);
uint64_t difficulty3 (0xffff000000000000);
uint64_t nonce1 (0);
uint64_t result_difficulty1 (0);
do
{
auto work1 = *pool.generate (nano::work_version::work_1, root, difficulty1);
nano::work_validate (nano::work_version::work_1, root, work1, &nonce1);
} while (nonce1 > difficulty2);
ASSERT_GT (nonce1, difficulty1);
uint64_t nonce2 (0);
result_difficulty1 = nano::work_difficulty (nano::work_version::work_1, root, work1);
} while (result_difficulty1 > difficulty2);
ASSERT_GT (result_difficulty1, difficulty1);
uint64_t result_difficulty2 (0);
do
{
auto work2 = *pool.generate (nano::work_version::work_1, root, difficulty2);
nano::work_validate (nano::work_version::work_1, root, work2, &nonce2);
} while (nonce2 > difficulty3);
ASSERT_GT (nonce2, difficulty2);
result_difficulty2 = nano::work_difficulty (nano::work_version::work_1, root, work2);
} while (result_difficulty2 > difficulty3);
ASSERT_GT (result_difficulty2, difficulty2);
}

TEST (work, eco_pow)
Expand All @@ -175,13 +168,13 @@ TEST (work, eco_pow)
nano::root root (1);
uint64_t difficulty1 (0xff00000000000000);
uint64_t difficulty2 (0xfff0000000000000);
uint64_t nonce (0);
uint64_t result_difficulty (0);
do
{
auto work = *pool.generate (nano::work_version::work_1, root, difficulty1);
nano::work_validate (nano::work_version::work_1, root, work, &nonce);
} while (nonce > difficulty2);
ASSERT_GT (nonce, difficulty1);
result_difficulty = nano::work_difficulty (nano::work_version::work_1, root, work);
} while (result_difficulty > difficulty2);
ASSERT_GT (result_difficulty, difficulty1);
}

promise.set_value_at_thread_exit (timer.stop ());
Expand Down
5 changes: 5 additions & 0 deletions nano/lib/blocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ nano::work_version nano::block::work_version () const
return nano::work_version::work_1;
}

uint64_t nano::block::difficulty () const
{
return nano::work_difficulty (this->work_version (), this->root (), this->block_work ());
}

nano::block_hash nano::block::generate_hash () const
{
nano::block_hash result;
Expand Down
1 change: 1 addition & 0 deletions nano/lib/blocks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class block
virtual bool valid_predecessor (nano::block const &) const = 0;
static size_t size (nano::block_type);
virtual nano::work_version work_version () const;
uint64_t difficulty () const;
// If there are any changes to the hashables, call this to update the cached hash
void refresh ();

Expand Down
40 changes: 27 additions & 13 deletions nano/lib/work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,48 @@ std::string nano::to_string (nano::work_version const version_a)
return result;
}

bool nano::work_validate (nano::block const & block_a, uint64_t * difficulty_a)
bool nano::work_validate (nano::block const & block_a)
{
return nano::work_validate (block_a.work_version (), block_a.root (), block_a.block_work (), difficulty_a);
return block_a.difficulty () < nano::work_threshold (block_a.work_version ());
}

bool nano::work_validate (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a, uint64_t * difficulty_a)
bool nano::work_validate (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
{
bool invalid (true);
return nano::work_difficulty (version_a, root_a, work_a) < nano::work_threshold (version_a);
}

uint64_t nano::work_difficulty (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
{
uint64_t result{ 0 };
switch (version_a)
{
case nano::work_version::work_1:
invalid = nano::work_v1::validate (root_a, work_a, difficulty_a);
result = nano::work_v1::value (root_a, work_a);
break;
default:
debug_assert (false && "Invalid version specified to work_validate");
debug_assert (false && "Invalid version specified to work_difficulty");
}
return invalid;
return result;
}

bool nano::work_v1::validate (nano::root const & root_a, uint64_t work_a, uint64_t * difficulty_a)
uint64_t nano::work_threshold (nano::work_version const version_a)
{
static nano::network_constants network_constants;
auto work_value (value (root_a, work_a));
if (difficulty_a != nullptr)
uint64_t result{ std::numeric_limits<uint64_t>::max () };
switch (version_a)
{
*difficulty_a = work_value;
case nano::work_version::work_1:
result = nano::work_v1::threshold ();
break;
default:
debug_assert (false && "Invalid version specified to work_threshold");
}
return work_value < network_constants.publish_threshold;
return result;
}

uint64_t nano::work_v1::threshold ()
{
static nano::network_constants network_constants;
return network_constants.publish_threshold;
}

#ifndef NANO_FUZZER_TEST
Expand Down
11 changes: 7 additions & 4 deletions nano/lib/work.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ enum class work_version
std::string to_string (nano::work_version const version_a);

class block;
bool work_validate (nano::block const &, uint64_t * = nullptr);
bool work_validate (nano::work_version const, nano::root const &, uint64_t const, uint64_t * = nullptr);
bool work_validate (nano::block const &);
bool work_validate (nano::work_version const, nano::root const &, uint64_t const);

uint64_t work_difficulty (nano::work_version const, nano::root const &, uint64_t const);
uint64_t work_threshold (nano::work_version const);

namespace work_v1
{
bool validate (nano::root const &, uint64_t const, uint64_t * = nullptr);
uint64_t value (nano::root const &, uint64_t);
uint64_t value (nano::root const & root_a, uint64_t work_a);
uint64_t threshold ();
}
class opencl_work;
class work_item final
Expand Down
10 changes: 2 additions & 8 deletions nano/node/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,10 +579,7 @@ std::pair<std::shared_ptr<nano::election>, bool> nano::active_transactions::inse
result.second = true;
auto hash (block_a->hash ());
result.first = nano::make_shared<nano::election> (node, block_a, skip_delay_a, confirmation_action_a);
uint64_t difficulty (0);
auto error (nano::work_validate (*block_a, &difficulty));
(void)error;
debug_assert (!error);
auto difficulty (block_a->difficulty ());
roots.get<tag_root> ().emplace (nano::conflict_info{ root, difficulty, difficulty, result.first });
blocks.emplace (hash, result.first);
adjust_difficulty (hash);
Expand Down Expand Up @@ -679,10 +676,7 @@ void nano::active_transactions::update_difficulty (std::shared_ptr<nano::block>
auto existing_election (roots.get<tag_root> ().find (block_a->qualified_root ()));
if (existing_election != roots.get<tag_root> ().end ())
{
uint64_t difficulty;
auto error (nano::work_validate (*block_a, &difficulty));
(void)error;
debug_assert (!error);
auto difficulty (block_a->difficulty ());
if (difficulty > existing_election->difficulty)
{
if (node.config.logging.active_update_logging ())
Expand Down
5 changes: 2 additions & 3 deletions nano/node/distributed_work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ void nano::distributed_work::success (std::string const & body_a, nano::tcp_endp
uint64_t work;
if (!nano::from_string_hex (work_text, work))
{
uint64_t result_difficulty (0);
if (!nano::work_validate (request.version, request.root, work, &result_difficulty) && result_difficulty >= request.difficulty)
if (nano::work_difficulty (request.version, request.root, work) >= request.difficulty)
{
error = false;
node.unresponsive_work_peers = false;
Expand Down Expand Up @@ -324,7 +323,7 @@ void nano::distributed_work::set_once (uint64_t const work_a, std::string const
if (node.config.logging.work_generation_time ())
{
boost::format unformatted_l ("Work generation for %1%, with a threshold difficulty of %2% (multiplier %3%x) complete: %4% ms");
auto multiplier_text_l (nano::to_string (nano::difficulty::to_multiplier (request.difficulty, node.network_params.network.publish_threshold), 2));
auto multiplier_text_l (nano::to_string (nano::difficulty::to_multiplier (request.difficulty, nano::work_threshold (request.version)), 2));
node.logger.try_log (boost::str (unformatted_l % request.root.to_string () % nano::to_string_hex (request.difficulty) % multiplier_text_l % elapsed.value ().count ()));
}
}
Expand Down
Loading