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

Work version concept #2569

Merged
merged 3 commits into from
Feb 19, 2020
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
4 changes: 2 additions & 2 deletions nano/core_test/active_transactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,8 @@ TEST (active_transactions, update_difficulty)
ASSERT_NO_ERROR (system.poll ());
}
// Update work with higher difficulty
auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1, boost::none);
auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1, boost::none);
auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1);
auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1);

std::error_code ec;
nano::state_block_builder builder;
Expand Down
24 changes: 12 additions & 12 deletions nano/core_test/distributed_work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ TEST (distributed_work, stopped)
{
nano::system system (1);
system.nodes[0]->distributed_work.stop ();
ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::block_hash (), {}, {}, nano::network_constants::publish_test_threshold));
ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::work_version::work_1, nano::block_hash (), {}, {}, nano::network_constants::publish_test_threshold));
}

TEST (distributed_work, no_peers)
Expand All @@ -25,7 +25,7 @@ TEST (distributed_work, no_peers)
work = work_a;
done = true;
};
ASSERT_FALSE (node->distributed_work.make (hash, node->config.work_peers, callback, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (!done)
{
Expand All @@ -47,7 +47,7 @@ TEST (distributed_work, no_peers_disabled)
nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.work_threads = 0;
auto & node = *system.add_node (node_config);
ASSERT_TRUE (node.distributed_work.make (nano::block_hash (), node.config.work_peers, {}, nano::network_constants::publish_test_threshold));
ASSERT_TRUE (node.distributed_work.make (nano::work_version::work_1, nano::block_hash (), node.config.work_peers, {}, nano::network_constants::publish_test_threshold));
}

TEST (distributed_work, no_peers_cancel)
Expand All @@ -63,7 +63,7 @@ TEST (distributed_work, no_peers_cancel)
ASSERT_FALSE (work_a.is_initialized ());
done = true;
};
ASSERT_FALSE (node.distributed_work.make (hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold)));
ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold)));
ASSERT_EQ (1, node.distributed_work.items.size ());
// cleanup should not cancel or remove an ongoing work
node.distributed_work.cleanup_finished ();
Expand All @@ -79,7 +79,7 @@ TEST (distributed_work, no_peers_cancel)

// now using observer
done = false;
ASSERT_FALSE (node.distributed_work.make (hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold)));
ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, callback_to_cancel, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_threshold)));
ASSERT_EQ (1, node.distributed_work.items.size ());
node.observers.work_cancel.notify (hash);
system.deadline_set (20s);
Expand All @@ -103,7 +103,7 @@ TEST (distributed_work, no_peers_multi)
// Test many works for the same root
for (unsigned i{ 0 }; i < total; ++i)
{
ASSERT_FALSE (node->distributed_work.make (hash, node->config.work_peers, callback, nano::difficulty::from_multiplier (10, node->network_params.network.publish_threshold)));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, nano::difficulty::from_multiplier (10, node->network_params.network.publish_threshold)));
}
// 1 root, and _total_ requests for that root are expected, but some may have already finished
ASSERT_EQ (1, node->distributed_work.items.size ());
Expand All @@ -128,7 +128,7 @@ TEST (distributed_work, no_peers_multi)
for (unsigned i{ 0 }; i < total; ++i)
{
nano::block_hash hash_i (i + 1);
ASSERT_FALSE (node->distributed_work.make (hash_i, node->config.work_peers, callback, node->network_params.network.publish_threshold));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash_i, node->config.work_peers, callback, node->network_params.network.publish_threshold));
}
// 10 roots expected with 1 work each, but some may have completed so test for some
ASSERT_GT (node->distributed_work.items.size (), 5);
Expand Down Expand Up @@ -171,7 +171,7 @@ TEST (distributed_work, peer)
work_peer->start ();
decltype (node->config.work_peers) peers;
peers.emplace_back ("::ffff:127.0.0.1", work_peer->port ());
ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (!done)
{
Expand Down Expand Up @@ -201,7 +201,7 @@ TEST (distributed_work, peer_malicious)
malicious_peer->start ();
decltype (node->config.work_peers) peers;
peers.emplace_back ("::ffff:127.0.0.1", malicious_peer->port ());
ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (!done)
{
Expand All @@ -226,7 +226,7 @@ TEST (distributed_work, peer_malicious)
auto malicious_peer2 (std::make_shared<fake_work_peer> (node->work, node->io_ctx, nano::get_available_port (), work_peer_type::malicious));
malicious_peer2->start ();
peers[0].second = malicious_peer2->port ();
ASSERT_FALSE (node->distributed_work.make (hash, peers, nullptr, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, nullptr, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (malicious_peer2->generations_bad < 2)
{
Expand Down Expand Up @@ -259,7 +259,7 @@ TEST (distributed_work, peer_multi)
peers.emplace_back ("localhost", malicious_peer->port ());
peers.emplace_back ("localhost", slow_peer->port ());
peers.emplace_back ("localhost", good_peer->port ());
ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (!done)
{
Expand Down Expand Up @@ -298,7 +298,7 @@ TEST (distributed_work, fail_resolve)
};
decltype (node->config.work_peers) peers;
peers.emplace_back ("beeb.boop.123z", 0);
ASSERT_FALSE (node->distributed_work.make (hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_threshold, nano::account ()));
system.deadline_set (5s);
while (!done)
{
Expand Down
2 changes: 1 addition & 1 deletion nano/core_test/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1190,7 +1190,7 @@ TEST (wallet, work_watcher_generation_disabled)
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));
node.wallets.watcher->add (block);
node.wallets.watcher->add (block, nano::work_version::work_1);
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);
Expand Down
1 change: 1 addition & 0 deletions nano/core_test/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ TEST (websocket, work)

ASSERT_EQ (1, contents.count ("request"));
auto & request = contents.get_child ("request");
ASSERT_EQ (request.get<std::string> ("version"), nano::to_string (nano::work_version::work_1));
ASSERT_EQ (request.get<std::string> ("hash"), hash.to_string ());
ASSERT_EQ (request.get<std::string> ("difficulty"), nano::to_string_hex (node1->network_params.network.publish_threshold));
ASSERT_EQ (request.get<double> ("multiplier"), 1.0);
Expand Down
4 changes: 2 additions & 2 deletions nano/core_test/work_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ TEST (work, opencl)
if (opencl != nullptr)
{
// 0 threads, should add 1 for managing OpenCL
nano::work_pool pool (0, std::chrono::nanoseconds (0), [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> & ticket_a) {
return opencl->generate_work (root_a, difficulty_a);
nano::work_pool pool (0, std::chrono::nanoseconds (0), [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> & ticket_a) {
return opencl->generate_work (version_a, root_a, difficulty_a);
});
ASSERT_NE (nullptr, pool.opencl);
nano::root root;
Expand Down
2 changes: 2 additions & 0 deletions nano/lib/errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ std::string nano::error_rpc_messages::message (int ev) const
return "Bad source";
case nano::error_rpc::bad_timeout:
return "Bad timeout number";
case nano::error_rpc::bad_work_version:
return "Bad work version";
case nano::error_rpc::block_create_balance_mismatch:
return "Balance mismatch for previous block";
case nano::error_rpc::block_create_key_required:
Expand Down
1 change: 1 addition & 0 deletions nano/lib/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ enum class error_rpc
bad_representative_number,
bad_source,
bad_timeout,
bad_work_version,
block_create_balance_mismatch,
block_create_key_required,
block_create_public_key_mismatch,
Expand Down
99 changes: 82 additions & 17 deletions nano/lib/work.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,65 @@

#include <future>

bool nano::work_validate (nano::root const & root_a, uint64_t work_a, uint64_t * difficulty_a)
std::string nano::to_string (nano::work_version const version_a)
{
static nano::network_constants network_constants;
auto value (nano::work_value (root_a, work_a));
if (difficulty_a != nullptr)
std::string result ("invalid");
switch (version_a)
{
case nano::work_version::work_1:
result = "work_1";
break;
case nano::work_version::unspecified:
result = "unspecified";
break;
}
return result;
}

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

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 invalid (true);
switch (version_a)
{
*difficulty_a = value;
case nano::work_version::work_1:
invalid = nano::work_v1::validate (root_a, work_a, difficulty_a);
break;
default:
assert (false && "Invalid version specified to work_validate");
}
return value < network_constants.publish_threshold;
return invalid;
}

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

bool nano::work_validate (nano::root const & root_a, uint64_t const work_a, uint64_t * difficulty_a)
{
static nano::network_constants network_constants;
assert (network_constants.is_test_network ());
return nano::work_validate (nano::work_version::work_1, root_a, work_a, difficulty_a);
}

bool nano::work_v1::validate (nano::root const & root_a, uint64_t work_a, uint64_t * difficulty_a)
{
static nano::network_constants network_constants;
auto work_value (value (root_a, work_a));
if (difficulty_a != nullptr)
{
*difficulty_a = work_value;
}
return work_value < network_constants.publish_threshold;
}

#ifndef NANO_FUZZER_TEST
uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
uint64_t nano::work_v1::value (nano::root const & root_a, uint64_t work_a)
{
uint64_t result;
blake2b_state hash;
Expand All @@ -34,7 +75,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
return result;
}
#else
uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
uint64_t nano::work_v1::value (nano::root const & root_a, uint64_t work_a)
{
static nano::network_constants network_constants;
if (!network_constants.is_test_network ())
Expand All @@ -46,7 +87,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
}
#endif

nano::work_pool::work_pool (unsigned max_threads_a, std::chrono::nanoseconds pow_rate_limiter_a, std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> opencl_a) :
nano::work_pool::work_pool (unsigned max_threads_a, std::chrono::nanoseconds pow_rate_limiter_a, std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> opencl_a) :
ticket (0),
done (false),
pow_rate_limiter (pow_rate_limiter_a),
Expand Down Expand Up @@ -108,12 +149,12 @@ void nano::work_pool::loop (uint64_t thread)
boost::optional<uint64_t> opt_work;
if (thread == 0 && opencl)
{
opt_work = opencl (current_l.item, current_l.difficulty, ticket);
opt_work = opencl (current_l.version, current_l.item, current_l.difficulty, ticket);
}
if (opt_work.is_initialized ())
{
work = *opt_work;
output = work_value (current_l.item, work);
output = nano::work_v1::value (current_l.item, work);
}
else
{
Expand Down Expand Up @@ -146,7 +187,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 (current_l.difficulty == 0 || work_value (current_l.item, work) == output);
assert (current_l.difficulty == 0 || nano::work_v1::value (current_l.item, work) == output);
// Signal other threads to stop their work next time they check ticket
++ticket;
pending.pop_front ();
Expand Down Expand Up @@ -206,17 +247,27 @@ void nano::work_pool::stop ()

void nano::work_pool::generate (nano::root const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a)
{
generate (root_a, callback_a, network_constants.publish_threshold);
generate (nano::work_version::work_1, root_a, callback_a);
}

void nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a)
{
generate (version_a, root_a, callback_a, network_constants.publish_threshold);
}

void nano::work_pool::generate (nano::root const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a, uint64_t difficulty_a)
{
generate (nano::work_version::work_1, root_a, callback_a, difficulty_a);
}

void nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a, uint64_t difficulty_a)
{
assert (!root_a.is_zero ());
if (!threads.empty ())
{
{
nano::lock_guard<std::mutex> lock (mutex);
pending.emplace_back (root_a, callback_a, difficulty_a);
pending.emplace_back (version_a, root_a, callback_a, difficulty_a);
}
producer_condition.notify_all ();
}
Expand All @@ -228,18 +279,32 @@ void nano::work_pool::generate (nano::root const & root_a, std::function<void(bo

boost::optional<uint64_t> nano::work_pool::generate (nano::root const & root_a)
{
return generate (root_a, network_constants.publish_threshold);
static nano::network_constants network_constants;
assert (network_constants.is_test_network ());
return generate (nano::work_version::work_1, root_a);
}

boost::optional<uint64_t> nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a)
{
return generate (version_a, root_a, network_constants.publish_threshold);
}

boost::optional<uint64_t> nano::work_pool::generate (nano::root const & root_a, uint64_t difficulty_a)
{
static nano::network_constants network_constants;
assert (network_constants.is_test_network ());
return generate (nano::work_version::work_1, root_a, difficulty_a);
}

boost::optional<uint64_t> nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a)
{
boost::optional<uint64_t> result;
if (!threads.empty ())
{
std::promise<boost::optional<uint64_t>> work;
std::future<boost::optional<uint64_t>> future = work.get_future ();
generate (
root_a, [&work](boost::optional<uint64_t> work_a) {
version_a, root_a, [&work](boost::optional<uint64_t> work_a) {
work.set_value (work_a);
},
difficulty_a);
Expand Down
Loading