Work version concept (#2569)

* Work version concept

Adds nano::work_version which is passed to all work_generate and work_validate methods (except for tests, ensured with an assert).

The functional changes are quite minimal, as every caller defaults to the only work version available (work_1):

- RPC work_generate, work_validate and block_create can receive an optional "work_version"
- The work websocket outputs the work version

These changes constitute the pipeline necessary for conditional work validation.

* Use nano::to_string to match the work version text
This commit is contained in:
Guilherme Lawless 2020-02-19 15:03:23 +00:00 committed by GitHub
commit eb5febfdf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 352 additions and 156 deletions

View file

@ -534,8 +534,8 @@ TEST (active_transactions, update_difficulty)
ASSERT_NO_ERROR (system.poll ()); ASSERT_NO_ERROR (system.poll ());
} }
// Update work with higher difficulty // Update work with higher difficulty
auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1, boost::none); auto work1 = node1.work_generate_blocking (send1->root (), difficulty1 + 1);
auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1, boost::none); auto work2 = node1.work_generate_blocking (send2->root (), difficulty2 + 1);
std::error_code ec; std::error_code ec;
nano::state_block_builder builder; nano::state_block_builder builder;

View file

@ -10,7 +10,7 @@ TEST (distributed_work, stopped)
{ {
nano::system system (1); nano::system system (1);
system.nodes[0]->distributed_work.stop (); 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) TEST (distributed_work, no_peers)
@ -25,7 +25,7 @@ TEST (distributed_work, no_peers)
work = work_a; work = work_a;
done = true; 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); system.deadline_set (5s);
while (!done) while (!done)
{ {
@ -47,7 +47,7 @@ TEST (distributed_work, no_peers_disabled)
nano::node_config node_config (nano::get_available_port (), system.logging); nano::node_config node_config (nano::get_available_port (), system.logging);
node_config.work_threads = 0; node_config.work_threads = 0;
auto & node = *system.add_node (node_config); 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) TEST (distributed_work, no_peers_cancel)
@ -63,7 +63,7 @@ TEST (distributed_work, no_peers_cancel)
ASSERT_FALSE (work_a.is_initialized ()); ASSERT_FALSE (work_a.is_initialized ());
done = true; 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 ()); ASSERT_EQ (1, node.distributed_work.items.size ());
// cleanup should not cancel or remove an ongoing work // cleanup should not cancel or remove an ongoing work
node.distributed_work.cleanup_finished (); node.distributed_work.cleanup_finished ();
@ -79,7 +79,7 @@ TEST (distributed_work, no_peers_cancel)
// now using observer // now using observer
done = false; 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 ()); ASSERT_EQ (1, node.distributed_work.items.size ());
node.observers.work_cancel.notify (hash); node.observers.work_cancel.notify (hash);
system.deadline_set (20s); system.deadline_set (20s);
@ -103,7 +103,7 @@ TEST (distributed_work, no_peers_multi)
// Test many works for the same root // Test many works for the same root
for (unsigned i{ 0 }; i < total; ++i) 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 // 1 root, and _total_ requests for that root are expected, but some may have already finished
ASSERT_EQ (1, node->distributed_work.items.size ()); ASSERT_EQ (1, node->distributed_work.items.size ());
@ -128,7 +128,7 @@ TEST (distributed_work, no_peers_multi)
for (unsigned i{ 0 }; i < total; ++i) for (unsigned i{ 0 }; i < total; ++i)
{ {
nano::block_hash hash_i (i + 1); 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 // 10 roots expected with 1 work each, but some may have completed so test for some
ASSERT_GT (node->distributed_work.items.size (), 5); ASSERT_GT (node->distributed_work.items.size (), 5);
@ -171,7 +171,7 @@ TEST (distributed_work, peer)
work_peer->start (); work_peer->start ();
decltype (node->config.work_peers) peers; decltype (node->config.work_peers) peers;
peers.emplace_back ("::ffff:127.0.0.1", work_peer->port ()); 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); system.deadline_set (5s);
while (!done) while (!done)
{ {
@ -201,7 +201,7 @@ TEST (distributed_work, peer_malicious)
malicious_peer->start (); malicious_peer->start ();
decltype (node->config.work_peers) peers; decltype (node->config.work_peers) peers;
peers.emplace_back ("::ffff:127.0.0.1", malicious_peer->port ()); 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); system.deadline_set (5s);
while (!done) while (!done)
{ {
@ -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)); 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 (); malicious_peer2->start ();
peers[0].second = malicious_peer2->port (); 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); system.deadline_set (5s);
while (malicious_peer2->generations_bad < 2) while (malicious_peer2->generations_bad < 2)
{ {
@ -259,7 +259,7 @@ TEST (distributed_work, peer_multi)
peers.emplace_back ("localhost", malicious_peer->port ()); peers.emplace_back ("localhost", malicious_peer->port ());
peers.emplace_back ("localhost", slow_peer->port ()); peers.emplace_back ("localhost", slow_peer->port ());
peers.emplace_back ("localhost", good_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); system.deadline_set (5s);
while (!done) while (!done)
{ {
@ -298,7 +298,7 @@ TEST (distributed_work, fail_resolve)
}; };
decltype (node->config.work_peers) peers; decltype (node->config.work_peers) peers;
peers.emplace_back ("beeb.boop.123z", 0); 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); system.deadline_set (5s);
while (!done) while (!done)
{ {

View file

@ -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 ()))); 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); uint64_t difficulty (0);
ASSERT_FALSE (nano::work_validate (*block, &difficulty)); 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_FALSE (node.process_local (block).code != nano::process_result::progress);
ASSERT_TRUE (node.wallets.watcher->is_watched (block->qualified_root ())); 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, node.network_params.network.publish_threshold);

View file

@ -677,6 +677,7 @@ TEST (websocket, work)
ASSERT_EQ (1, contents.count ("request")); ASSERT_EQ (1, contents.count ("request"));
auto & request = contents.get_child ("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> ("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<std::string> ("difficulty"), nano::to_string_hex (node1->network_params.network.publish_threshold));
ASSERT_EQ (request.get<double> ("multiplier"), 1.0); ASSERT_EQ (request.get<double> ("multiplier"), 1.0);

View file

@ -96,8 +96,8 @@ TEST (work, opencl)
if (opencl != nullptr) if (opencl != nullptr)
{ {
// 0 threads, should add 1 for managing OpenCL // 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) { 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 (root_a, difficulty_a); return opencl->generate_work (version_a, root_a, difficulty_a);
}); });
ASSERT_NE (nullptr, pool.opencl); ASSERT_NE (nullptr, pool.opencl);
nano::root root; nano::root root;

View file

@ -144,6 +144,8 @@ std::string nano::error_rpc_messages::message (int ev) const
return "Bad source"; return "Bad source";
case nano::error_rpc::bad_timeout: case nano::error_rpc::bad_timeout:
return "Bad timeout number"; return "Bad timeout number";
case nano::error_rpc::bad_work_version:
return "Bad work version";
case nano::error_rpc::block_create_balance_mismatch: case nano::error_rpc::block_create_balance_mismatch:
return "Balance mismatch for previous block"; return "Balance mismatch for previous block";
case nano::error_rpc::block_create_key_required: case nano::error_rpc::block_create_key_required:

View file

@ -84,6 +84,7 @@ enum class error_rpc
bad_representative_number, bad_representative_number,
bad_source, bad_source,
bad_timeout, bad_timeout,
bad_work_version,
block_create_balance_mismatch, block_create_balance_mismatch,
block_create_key_required, block_create_key_required,
block_create_public_key_mismatch, block_create_public_key_mismatch,

View file

@ -6,24 +6,65 @@
#include <future> #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; std::string result ("invalid");
auto value (nano::work_value (root_a, work_a)); switch (version_a)
if (difficulty_a != nullptr)
{ {
*difficulty_a = value; case nano::work_version::work_1:
result = "work_1";
break;
case nano::work_version::unspecified:
result = "unspecified";
break;
} }
return value < network_constants.publish_threshold; 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)
{
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 invalid;
} }
bool nano::work_validate (nano::block const & block_a, uint64_t * difficulty_a) 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 #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; uint64_t result;
blake2b_state hash; blake2b_state hash;
@ -34,7 +75,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
return result; return result;
} }
#else #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; static nano::network_constants network_constants;
if (!network_constants.is_test_network ()) if (!network_constants.is_test_network ())
@ -46,7 +87,7 @@ uint64_t nano::work_value (nano::root const & root_a, uint64_t work_a)
} }
#endif #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), ticket (0),
done (false), done (false),
pow_rate_limiter (pow_rate_limiter_a), pow_rate_limiter (pow_rate_limiter_a),
@ -108,12 +149,12 @@ void nano::work_pool::loop (uint64_t thread)
boost::optional<uint64_t> opt_work; boost::optional<uint64_t> opt_work;
if (thread == 0 && opencl) 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 ()) if (opt_work.is_initialized ())
{ {
work = *opt_work; work = *opt_work;
output = work_value (current_l.item, work); output = nano::work_v1::value (current_l.item, work);
} }
else else
{ {
@ -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 // If the ticket matches what we started with, we're the ones that found the solution
assert (output >= current_l.difficulty); 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 // Signal other threads to stop their work next time they check ticket
++ticket; ++ticket;
pending.pop_front (); pending.pop_front ();
@ -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) 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) 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 ()); assert (!root_a.is_zero ());
if (!threads.empty ()) if (!threads.empty ())
{ {
{ {
nano::lock_guard<std::mutex> lock (mutex); 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 (); producer_condition.notify_all ();
} }
@ -228,10 +279,24 @@ 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) 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) 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; boost::optional<uint64_t> result;
if (!threads.empty ()) if (!threads.empty ())
@ -239,7 +304,7 @@ boost::optional<uint64_t> nano::work_pool::generate (nano::root const & root_a,
std::promise<boost::optional<uint64_t>> work; std::promise<boost::optional<uint64_t>> work;
std::future<boost::optional<uint64_t>> future = work.get_future (); std::future<boost::optional<uint64_t>> future = work.get_future ();
generate ( 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); work.set_value (work_a);
}, },
difficulty_a); difficulty_a);

View file

@ -13,20 +13,35 @@
namespace nano namespace nano
{ {
class block; enum class work_version
{
unspecified,
work_1
};
std::string to_string (nano::work_version const version_a);
bool work_validate (nano::root const &, uint64_t, uint64_t * = nullptr); class block;
bool work_validate (nano::work_version const, nano::block const &, uint64_t * = nullptr);
bool work_validate (nano::work_version const, nano::root const &, uint64_t const, uint64_t * = nullptr);
// For tests only
bool work_validate (nano::block const &, uint64_t * = nullptr); bool work_validate (nano::block const &, uint64_t * = nullptr);
uint64_t work_value (nano::root const &, uint64_t); // For tests only
bool work_validate (nano::root const &, uint64_t const, uint64_t * = nullptr);
namespace work_v1
{
bool validate (nano::root const &, uint64_t const, uint64_t * = nullptr);
uint64_t value (nano::root const &, uint64_t);
}
class opencl_work; class opencl_work;
class work_item final class work_item final
{ {
public: public:
work_item (nano::root const & item_a, std::function<void(boost::optional<uint64_t> const &)> const & callback_a, uint64_t difficulty_a) : work_item (nano::work_version const version_a, nano::root const & item_a, std::function<void(boost::optional<uint64_t> const &)> const & callback_a, uint64_t difficulty_a) :
item (item_a), callback (callback_a), difficulty (difficulty_a) version (version_a), item (item_a), callback (callback_a), difficulty (difficulty_a)
{ {
} }
nano::work_version version;
nano::root item; nano::root item;
std::function<void(boost::optional<uint64_t> const &)> callback; std::function<void(boost::optional<uint64_t> const &)> callback;
uint64_t difficulty; uint64_t difficulty;
@ -34,12 +49,18 @@ public:
class work_pool final class work_pool final
{ {
public: public:
work_pool (unsigned, std::chrono::nanoseconds = std::chrono::nanoseconds (0), std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> = nullptr); work_pool (unsigned, std::chrono::nanoseconds = std::chrono::nanoseconds (0), std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> = nullptr);
~work_pool (); ~work_pool ();
void loop (uint64_t); void loop (uint64_t);
void stop (); void stop ();
void cancel (nano::root const &); void cancel (nano::root const &);
void generate (nano::work_version const, nano::root const &, std::function<void(boost::optional<uint64_t> const &)>);
void generate (nano::work_version const, nano::root const &, std::function<void(boost::optional<uint64_t> const &)>, uint64_t);
boost::optional<uint64_t> generate (nano::work_version const, nano::root const &);
boost::optional<uint64_t> generate (nano::work_version const, nano::root const &, uint64_t);
// For tests only
void generate (nano::root const &, std::function<void(boost::optional<uint64_t> const &)>); void generate (nano::root const &, std::function<void(boost::optional<uint64_t> const &)>);
// For tests only
void generate (nano::root const &, std::function<void(boost::optional<uint64_t> const &)>, uint64_t); void generate (nano::root const &, std::function<void(boost::optional<uint64_t> const &)>, uint64_t);
boost::optional<uint64_t> generate (nano::root const &); boost::optional<uint64_t> generate (nano::root const &);
boost::optional<uint64_t> generate (nano::root const &, uint64_t); boost::optional<uint64_t> generate (nano::root const &, uint64_t);
@ -52,7 +73,7 @@ public:
std::mutex mutex; std::mutex mutex;
nano::condition_variable producer_condition; nano::condition_variable producer_condition;
std::chrono::nanoseconds pow_rate_limiter; std::chrono::nanoseconds pow_rate_limiter;
std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> opencl; std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> opencl;
nano::observer_set<bool> work_observers; nano::observer_set<bool> work_observers;
}; };

View file

@ -47,10 +47,10 @@ void nano_daemon::daemon::run (boost::filesystem::path const & data_path, nano::
nano::logger_mt logger{ config.node.logging.min_time_between_log_output }; nano::logger_mt logger{ config.node.logging.min_time_between_log_output };
boost::asio::io_context io_ctx; boost::asio::io_context io_ctx;
auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger)); auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger));
nano::work_pool opencl_work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> & ticket_a) { nano::work_pool opencl_work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&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 (root_a, difficulty_a, ticket_a); return opencl->generate_work (version_a, root_a, difficulty_a, ticket_a);
} }
: std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> (nullptr)); : std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> (nullptr));
nano::alarm alarm (io_ctx); nano::alarm alarm (io_ctx);
try try
{ {

View file

@ -193,7 +193,7 @@ int main (int argc, char * const * argv)
<< "Account: " << rep.pub.to_account () << "\n"; << "Account: " << rep.pub.to_account () << "\n";
} }
nano::uint128_t balance (std::numeric_limits<nano::uint128_t>::max ()); nano::uint128_t balance (std::numeric_limits<nano::uint128_t>::max ());
nano::open_block genesis_block (reinterpret_cast<const nano::block_hash &> (genesis.pub), genesis.pub, genesis.pub, genesis.prv, genesis.pub, *work.generate (genesis.pub)); nano::open_block genesis_block (reinterpret_cast<const nano::block_hash &> (genesis.pub), genesis.pub, genesis.pub, genesis.prv, genesis.pub, *work.generate (nano::work_version::work_1, genesis.pub));
std::cout << genesis_block.to_json (); std::cout << genesis_block.to_json ();
std::cout.flush (); std::cout.flush ();
nano::block_hash previous (genesis_block.hash ()); nano::block_hash previous (genesis_block.hash ());
@ -205,7 +205,7 @@ int main (int argc, char * const * argv)
{ {
assert (balance > weekly_distribution); assert (balance > weekly_distribution);
balance = balance < (weekly_distribution * 2) ? 0 : balance - weekly_distribution; balance = balance < (weekly_distribution * 2) ? 0 : balance - weekly_distribution;
nano::send_block send (previous, landing.pub, balance, genesis.prv, genesis.pub, *work.generate (previous)); nano::send_block send (previous, landing.pub, balance, genesis.prv, genesis.pub, *work.generate (nano::work_version::work_1, previous));
previous = send.hash (); previous = send.hash ();
std::cout << send.to_json (); std::cout << send.to_json ();
std::cout.flush (); std::cout.flush ();
@ -321,7 +321,7 @@ int main (int argc, char * const * argv)
{ {
block.hashables.previous.qwords[0] += 1; block.hashables.previous.qwords[0] += 1;
auto begin1 (std::chrono::high_resolution_clock::now ()); auto begin1 (std::chrono::high_resolution_clock::now ());
block.block_work_set (*work.generate (block.root ())); block.block_work_set (*work.generate (nano::work_version::work_1, block.root ()));
auto end1 (std::chrono::high_resolution_clock::now ()); auto end1 (std::chrono::high_resolution_clock::now ());
std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast<std::chrono::microseconds> (end1 - begin1).count ()); std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast<std::chrono::microseconds> (end1 - begin1).count ());
} }
@ -336,7 +336,7 @@ int main (int argc, char * const * argv)
uint64_t count{ 10000000U }; // 10M uint64_t count{ 10000000U }; // 10M
for (uint64_t i (0); i < count; ++i) for (uint64_t i (0); i < count; ++i)
{ {
valid = nano::work_value (hash, i) > difficulty; valid = nano::work_v1::value (hash, i) > difficulty;
} }
std::ostringstream oss (valid ? "true" : "false"); // IO forces compiler to not dismiss the variable std::ostringstream oss (valid ? "true" : "false"); // IO forces compiler to not dismiss the variable
auto total_time (std::chrono::duration_cast<std::chrono::nanoseconds> (std::chrono::steady_clock::now () - start).count ()); auto total_time (std::chrono::duration_cast<std::chrono::nanoseconds> (std::chrono::steady_clock::now () - start).count ());
@ -419,17 +419,17 @@ int main (int argc, char * const * argv)
nano::logger_mt logger; nano::logger_mt logger;
nano::opencl_config config (platform, device, threads); nano::opencl_config config (platform, device, threads);
auto opencl (nano::opencl_work::create (true, config, logger)); auto opencl (nano::opencl_work::create (true, config, logger));
nano::work_pool work_pool (std::numeric_limits<unsigned>::max (), std::chrono::nanoseconds (0), opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> &) { nano::work_pool work_pool (std::numeric_limits<unsigned>::max (), std::chrono::nanoseconds (0), opencl ? [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> &) {
return opencl->generate_work (root_a, difficulty_a); return opencl->generate_work (version_a, root_a, difficulty_a);
} }
: std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> (nullptr)); : std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> (nullptr));
nano::change_block block (0, 0, nano::keypair ().prv, 0, 0); nano::change_block block (0, 0, nano::keypair ().prv, 0, 0);
std::cerr << boost::str (boost::format ("Starting OpenCL generation profiling. Platform: %1%. Device: %2%. Threads: %3%. Difficulty: %4$#x\n") % platform % device % threads % difficulty); std::cerr << boost::str (boost::format ("Starting OpenCL generation profiling. Platform: %1%. Device: %2%. Threads: %3%. Difficulty: %4$#x\n") % platform % device % threads % difficulty);
for (uint64_t i (0); true; ++i) for (uint64_t i (0); true; ++i)
{ {
block.hashables.previous.qwords[0] += 1; block.hashables.previous.qwords[0] += 1;
auto begin1 (std::chrono::high_resolution_clock::now ()); auto begin1 (std::chrono::high_resolution_clock::now ());
block.block_work_set (*work_pool.generate (block.root (), difficulty)); block.block_work_set (*work_pool.generate (nano::work_version::work_1, block.root (), difficulty));
auto end1 (std::chrono::high_resolution_clock::now ()); auto end1 (std::chrono::high_resolution_clock::now ());
std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast<std::chrono::microseconds> (end1 - begin1).count ()); std::cerr << boost::str (boost::format ("%|1$ 12d|\n") % std::chrono::duration_cast<std::chrono::microseconds> (end1 - begin1).count ());
} }
@ -738,7 +738,7 @@ int main (int argc, char * const * argv)
.balance (genesis_balance) .balance (genesis_balance)
.link (keys[i].pub) .link (keys[i].pub)
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
.work (*work.generate (genesis_latest)) .work (*work.generate (nano::work_version::work_1, genesis_latest))
.build (); .build ();
genesis_latest = send->hash (); genesis_latest = send->hash ();
@ -751,7 +751,7 @@ int main (int argc, char * const * argv)
.balance (balances[i]) .balance (balances[i])
.link (genesis_latest) .link (genesis_latest)
.sign (keys[i].prv, keys[i].pub) .sign (keys[i].prv, keys[i].pub)
.work (*work.generate (keys[i].pub)) .work (*work.generate (nano::work_version::work_1, keys[i].pub))
.build (); .build ();
frontiers[i] = open->hash (); frontiers[i] = open->hash ();
@ -772,7 +772,7 @@ int main (int argc, char * const * argv)
.balance (balances[j]) .balance (balances[j])
.link (keys[other].pub) .link (keys[other].pub)
.sign (keys[j].prv, keys[j].pub) .sign (keys[j].prv, keys[j].pub)
.work (*work.generate (frontiers[j])) .work (*work.generate (nano::work_version::work_1, frontiers[j]))
.build (); .build ();
frontiers[j] = send->hash (); frontiers[j] = send->hash ();
@ -787,7 +787,7 @@ int main (int argc, char * const * argv)
.balance (balances[other]) .balance (balances[other])
.link (static_cast<nano::block_hash const &> (frontiers[j])) .link (static_cast<nano::block_hash const &> (frontiers[j]))
.sign (keys[other].prv, keys[other].pub) .sign (keys[other].prv, keys[other].pub)
.work (*work.generate (frontiers[other])) .work (*work.generate (nano::work_version::work_1, frontiers[other]))
.build (); .build ();
frontiers[other] = receive->hash (); frontiers[other] = receive->hash ();
@ -859,7 +859,7 @@ int main (int argc, char * const * argv)
.balance (genesis_balance) .balance (genesis_balance)
.link (keys[i].pub) .link (keys[i].pub)
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
.work (*work.generate (genesis_latest)) .work (*work.generate (nano::work_version::work_1, genesis_latest))
.build (); .build ();
genesis_latest = send->hash (); genesis_latest = send->hash ();
@ -872,7 +872,7 @@ int main (int argc, char * const * argv)
.balance (balance) .balance (balance)
.link (genesis_latest) .link (genesis_latest)
.sign (keys[i].prv, keys[i].pub) .sign (keys[i].prv, keys[i].pub)
.work (*work.generate (keys[i].pub)) .work (*work.generate (nano::work_version::work_1, keys[i].pub))
.build (); .build ();
node->ledger.process (transaction, *open); node->ledger.process (transaction, *open);
@ -891,7 +891,7 @@ int main (int argc, char * const * argv)
.balance (genesis_balance) .balance (genesis_balance)
.link (destination.pub) .link (destination.pub)
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub) .sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
.work (*work.generate (genesis_latest)) .work (*work.generate (nano::work_version::work_1, genesis_latest))
.build (); .build ();
genesis_latest = send->hash (); genesis_latest = send->hash ();
@ -1104,7 +1104,7 @@ int main (int argc, char * const * argv)
std::cerr << boost::str (boost::format ("Incorrect sideband block details for block %1%\n") % hash.to_string ()); std::cerr << boost::str (boost::format ("Incorrect sideband block details for block %1%\n") % hash.to_string ());
} }
// Check if block work value is correct // Check if block work value is correct
if (nano::work_validate (*block.get ())) if (nano::work_validate (nano::work_version::work_1, *block))
{ {
std::cerr << boost::str (boost::format ("Invalid work for block %1% value: %2%\n") % hash.to_string () % nano::to_string_hex (block->block_work ())); std::cerr << boost::str (boost::format ("Invalid work for block %1% value: %2%\n") % hash.to_string () % nano::to_string_hex (block->block_work ()));
} }
@ -1416,4 +1416,4 @@ bool address_library_pair::operator== (const address_library_pair & other) const
{ {
return address == other.address; return address == other.address;
} }
} }

View file

@ -108,10 +108,10 @@ int run_wallet (QApplication & application, int argc, char * const * argv, boost
std::shared_ptr<nano_qt::wallet> gui; std::shared_ptr<nano_qt::wallet> gui;
nano::set_application_icon (application); nano::set_application_icon (application);
auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger)); auto opencl (nano::opencl_work::create (config.opencl_enable, config.opencl, logger));
nano::work_pool work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> &) { nano::work_pool work (config.node.work_threads, config.node.pow_sleep_interval, opencl ? [&opencl](nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::atomic<int> &) {
return opencl->generate_work (root_a, difficulty_a); return opencl->generate_work (version_a, root_a, difficulty_a);
} }
: std::function<boost::optional<uint64_t> (nano::root const &, uint64_t, std::atomic<int> &)> (nullptr)); : std::function<boost::optional<uint64_t> (nano::work_version const, nano::root const &, uint64_t, std::atomic<int> &)> (nullptr));
nano::alarm alarm (io_ctx); nano::alarm alarm (io_ctx);
node = std::make_shared<nano::node> (io_ctx, data_path, alarm, config.node, work, flags); node = std::make_shared<nano::node> (io_ctx, data_path, alarm, config.node, work, flags);
if (!node->init_error ()) if (!node->init_error ())

View file

@ -582,7 +582,7 @@ std::pair<std::shared_ptr<nano::election>, bool> nano::active_transactions::inse
auto hash (block_a->hash ()); auto hash (block_a->hash ());
result.first = nano::make_shared<nano::election> (node, block_a, skip_delay_a, confirmation_action_a); result.first = nano::make_shared<nano::election> (node, block_a, skip_delay_a, confirmation_action_a);
uint64_t difficulty (0); uint64_t difficulty (0);
release_assert (!nano::work_validate (*block_a, &difficulty)); release_assert (!nano::work_validate (nano::work_version::work_1, *block_a, &difficulty));
roots.get<tag_root> ().emplace (nano::conflict_info{ root, difficulty, difficulty, result.first }); roots.get<tag_root> ().emplace (nano::conflict_info{ root, difficulty, difficulty, result.first });
blocks.emplace (hash, result.first); blocks.emplace (hash, result.first);
adjust_difficulty (hash); adjust_difficulty (hash);
@ -680,7 +680,7 @@ void nano::active_transactions::update_difficulty (std::shared_ptr<nano::block>
if (existing_election != roots.get<tag_root> ().end ()) if (existing_election != roots.get<tag_root> ().end ())
{ {
uint64_t difficulty; uint64_t difficulty;
auto error (nano::work_validate (*block_a, &difficulty)); auto error (nano::work_validate (nano::work_version::work_1, *block_a, &difficulty));
(void)error; (void)error;
assert (!error); assert (!error);
if (difficulty > existing_election->difficulty) if (difficulty > existing_election->difficulty)
@ -714,7 +714,7 @@ void nano::active_transactions::update_difficulty (std::shared_ptr<nano::block>
{ {
uint64_t existing_difficulty; uint64_t existing_difficulty;
uint64_t new_difficulty; uint64_t new_difficulty;
if (!nano::work_validate (*block_a, &new_difficulty) && !nano::work_validate (*existing_block, &existing_difficulty)) if (!nano::work_validate (nano::work_version::work_1, *block_a, &new_difficulty) && !nano::work_validate (nano::work_version::work_1, *existing_block, &existing_difficulty))
{ {
if (new_difficulty > existing_difficulty) if (new_difficulty > existing_difficulty)
{ {

View file

@ -69,7 +69,7 @@ void nano::block_processor::add (std::shared_ptr<nano::block> block_a, uint64_t
void nano::block_processor::add (nano::unchecked_info const & info_a) void nano::block_processor::add (nano::unchecked_info const & info_a)
{ {
if (!nano::work_validate (info_a.block->root (), info_a.block->block_work ())) if (!nano::work_validate (nano::work_version::work_1, info_a.block->root (), info_a.block->block_work ()))
{ {
{ {
auto hash (info_a.block->hash ()); auto hash (info_a.block->hash ());
@ -375,7 +375,7 @@ void nano::block_processor::process_live (nano::block_hash const & hash_a, std::
// Add to work watcher to prevent dropping the election // Add to work watcher to prevent dropping the election
if (watch_work_a) if (watch_work_a)
{ {
node.wallets.watcher->add (block_a); node.wallets.watcher->add (block_a, nano::work_version::work_1);
} }
// Start collecting quorum on block // Start collecting quorum on block

View file

@ -214,7 +214,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
{ {
nano::bufferstream stream (connection->receive_buffer->data (), size_a); nano::bufferstream stream (connection->receive_buffer->data (), size_a);
std::shared_ptr<nano::block> block (nano::deserialize_block (stream, type_a)); std::shared_ptr<nano::block> block (nano::deserialize_block (stream, type_a));
if (block != nullptr && !nano::work_validate (*block)) if (block != nullptr && !nano::work_validate (nano::work_version::work_1, *block))
{ {
auto hash (block->hash ()); auto hash (block->hash ());
if (connection->node->config.logging.bulk_pull_logging ()) if (connection->node->config.logging.bulk_pull_logging ())

View file

@ -240,7 +240,7 @@ void nano::bulk_push_server::received_block (boost::system::error_code const & e
{ {
nano::bufferstream stream (receive_buffer->data (), size_a); nano::bufferstream stream (receive_buffer->data (), size_a);
auto block (nano::deserialize_block (stream, type_a)); auto block (nano::deserialize_block (stream, type_a));
if (block != nullptr && !nano::work_validate (*block)) if (block != nullptr && !nano::work_validate (nano::work_version::work_1, *block))
{ {
connection->node->process_active (std::move (block)); connection->node->process_active (std::move (block));
throttled_receive (); throttled_receive ();

View file

@ -418,7 +418,7 @@ void nano::message_parser::deserialize_publish (nano::stream & stream_a, nano::m
nano::publish incoming (error, stream_a, header_a, &block_uniquer); nano::publish incoming (error, stream_a, header_a, &block_uniquer);
if (!error && at_end (stream_a)) if (!error && at_end (stream_a))
{ {
if (!nano::work_validate (*incoming.block)) if (!nano::work_validate (nano::work_version::work_1, *incoming.block))
{ {
visitor.publish (incoming); visitor.publish (incoming);
} }
@ -439,7 +439,7 @@ void nano::message_parser::deserialize_confirm_req (nano::stream & stream_a, nan
nano::confirm_req incoming (error, stream_a, header_a, &block_uniquer); nano::confirm_req incoming (error, stream_a, header_a, &block_uniquer);
if (!error && at_end (stream_a)) if (!error && at_end (stream_a))
{ {
if (incoming.block == nullptr || !nano::work_validate (*incoming.block)) if (incoming.block == nullptr || !nano::work_validate (nano::work_version::work_1, *incoming.block))
{ {
visitor.confirm_req (incoming); visitor.confirm_req (incoming);
} }
@ -465,7 +465,7 @@ void nano::message_parser::deserialize_confirm_ack (nano::stream & stream_a, nan
if (!vote_block.which ()) if (!vote_block.which ())
{ {
auto block (boost::get<std::shared_ptr<nano::block>> (vote_block)); auto block (boost::get<std::shared_ptr<nano::block>> (vote_block));
if (nano::work_validate (*block)) if (nano::work_validate (nano::work_version::work_1, *block))
{ {
status = parse_status::insufficient_work; status = parse_status::insufficient_work;
break; break;

View file

@ -43,15 +43,15 @@ nano::distributed_work::~distributed_work ()
nano::websocket::message_builder builder; nano::websocket::message_builder builder;
if (status == work_generation_status::success) if (status == work_generation_status::success)
{ {
node_l->websocket_server->broadcast (builder.work_generation (request.root, work_result, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), winner, bad_peers)); node_l->websocket_server->broadcast (builder.work_generation (request.version, request.root, work_result, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), winner, bad_peers));
} }
else if (status == work_generation_status::cancelled) else if (status == work_generation_status::cancelled)
{ {
node_l->websocket_server->broadcast (builder.work_cancelled (request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); node_l->websocket_server->broadcast (builder.work_cancelled (request.version, request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers));
} }
else if (status == work_generation_status::failure_local || status == work_generation_status::failure_peers) else if (status == work_generation_status::failure_local || status == work_generation_status::failure_peers)
{ {
node_l->websocket_server->broadcast (builder.work_failed (request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers)); node_l->websocket_server->broadcast (builder.work_failed (request.version, request.root, request.difficulty, node_l->network_params.network.publish_threshold, elapsed.value (), bad_peers));
} }
} }
stop_once (true); stop_once (true);
@ -108,7 +108,7 @@ void nano::distributed_work::start_local ()
auto this_l (shared_from_this ()); auto this_l (shared_from_this ());
local_generation_started = true; local_generation_started = true;
node.work.generate ( node.work.generate (
request.root, [this_l](boost::optional<uint64_t> const & work_a) { request.version, request.root, [this_l](boost::optional<uint64_t> const & work_a) {
if (work_a.is_initialized ()) if (work_a.is_initialized ())
{ {
this_l->set_once (*work_a); this_l->set_once (*work_a);
@ -242,7 +242,7 @@ void nano::distributed_work::success (std::string const & body_a, nano::tcp_endp
if (!nano::from_string_hex (work_text, work)) if (!nano::from_string_hex (work_text, work))
{ {
uint64_t result_difficulty (0); uint64_t result_difficulty (0);
if (!nano::work_validate (request.root, work, &result_difficulty) && result_difficulty >= request.difficulty) if (!nano::work_validate (request.version, request.root, work, &result_difficulty) && result_difficulty >= request.difficulty)
{ {
error = false; error = false;
node.unresponsive_work_peers = false; node.unresponsive_work_peers = false;

View file

@ -6,6 +6,7 @@
#include <nano/boost/beast/http/string_body.hpp> #include <nano/boost/beast/http/string_body.hpp>
#include <nano/lib/numbers.hpp> #include <nano/lib/numbers.hpp>
#include <nano/lib/timer.hpp> #include <nano/lib/timer.hpp>
#include <nano/lib/work.hpp>
#include <nano/node/common.hpp> #include <nano/node/common.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
@ -28,6 +29,7 @@ class node;
struct work_request final struct work_request final
{ {
nano::work_version version;
nano::root root; nano::root root;
uint64_t difficulty; uint64_t difficulty;
boost::optional<nano::account> const account; boost::optional<nano::account> const account;

View file

@ -11,9 +11,9 @@ nano::distributed_work_factory::~distributed_work_factory ()
stop (); stop ();
} }
bool nano::distributed_work_factory::make (nano::root const & root_a, std::vector<std::pair<std::string, uint16_t>> const & peers_a, std::function<void(boost::optional<uint64_t>)> const & callback_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a) bool nano::distributed_work_factory::make (nano::work_version const version_a, nano::root const & root_a, std::vector<std::pair<std::string, uint16_t>> const & peers_a, std::function<void(boost::optional<uint64_t>)> const & callback_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a)
{ {
return make (std::chrono::seconds (1), nano::work_request{ root_a, difficulty_a, account_a, callback_a, peers_a }); return make (std::chrono::seconds (1), nano::work_request{ version_a, root_a, difficulty_a, account_a, callback_a, peers_a });
} }
bool nano::distributed_work_factory::make (std::chrono::seconds const & backoff_a, nano::work_request const & request_a) bool nano::distributed_work_factory::make (std::chrono::seconds const & backoff_a, nano::work_request const & request_a)

View file

@ -22,7 +22,7 @@ class distributed_work_factory final
public: public:
distributed_work_factory (nano::node &); distributed_work_factory (nano::node &);
~distributed_work_factory (); ~distributed_work_factory ();
bool make (nano::root const &, std::vector<std::pair<std::string, uint16_t>> const &, std::function<void(boost::optional<uint64_t>)> const &, uint64_t, boost::optional<nano::account> const & = boost::none); bool make (nano::work_version const, nano::root const &, std::vector<std::pair<std::string, uint16_t>> const &, std::function<void(boost::optional<uint64_t>)> const &, uint64_t, boost::optional<nano::account> const & = boost::none);
bool make (std::chrono::seconds const &, nano::work_request const &); bool make (std::chrono::seconds const &, nano::work_request const &);
void cancel (nano::root const &, bool const local_stop = false); void cancel (nano::root const &, bool const local_stop = false);
void cleanup_finished (); void cleanup_finished ();
@ -36,4 +36,4 @@ public:
class container_info_component; class container_info_component;
std::unique_ptr<container_info_component> collect_container_info (distributed_work_factory & distributed_work, const std::string & name); std::unique_ptr<container_info_component> collect_container_info (distributed_work_factory & distributed_work, const std::string & name);
} }

View file

@ -375,6 +375,24 @@ double nano::json_handler::multiplier_optional_impl (uint64_t & difficulty)
return multiplier; return multiplier;
} }
nano::work_version nano::json_handler::work_version_optional_impl (nano::work_version const default_a)
{
nano::work_version result = default_a;
boost::optional<std::string> version_text (request.get_optional<std::string> ("version"));
if (!ec && version_text.is_initialized ())
{
if (*version_text == nano::to_string (nano::work_version::work_1))
{
result = nano::work_version::work_1;
}
else
{
ec = nano::error_rpc::bad_work_version;
}
}
return result;
}
namespace namespace
{ {
bool decode_unsigned (std::string const & text, uint64_t & number) bool decode_unsigned (std::string const & text, uint64_t & number)
@ -697,7 +715,7 @@ void nano::json_handler::account_representative_set ()
auto info (rpc_l->account_info_impl (block_transaction, account)); auto info (rpc_l->account_info_impl (block_transaction, account));
if (!rpc_l->ec) if (!rpc_l->ec)
{ {
if (nano::work_validate (info.head, work)) if (nano::work_validate (nano::work_version::work_1, info.head, work))
{ {
rpc_l->ec = nano::error_common::invalid_work; rpc_l->ec = nano::error_common::invalid_work;
} }
@ -1277,6 +1295,8 @@ void nano::json_handler::block_create ()
} }
} }
auto work (work_optional_impl ()); auto work (work_optional_impl ());
// Default to work_1 if not specified
auto work_version (work_version_optional_impl (nano::work_version::work_1));
nano::raw_key prv; nano::raw_key prv;
prv.data.clear (); prv.data.clear ();
nano::block_hash previous (0); nano::block_hash previous (0);
@ -1542,7 +1562,7 @@ void nano::json_handler::block_create ()
{ {
if (work == 0) if (work == 0)
{ {
node.work_generate (root_l, get_callback_l (block_l), nano::account (pub)); node.work_generate (work_version, root_l, get_callback_l (block_l), nano::account (pub));
} }
else else
{ {
@ -2103,10 +2123,10 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
.balance (info.balance) .balance (info.balance)
.link (link) .link (link)
.sign (raw_key, signer) .sign (raw_key, signer)
.work (node_a->work_generate_blocking (info.head).value_or (0)) .work (node_a->work_generate_blocking (nano::work_version::work_1, info.head).value_or (0))
.build (); .build ();
bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ()));
bool valid_work (!nano::work_validate (*epoch.get ())); bool valid_work (!nano::work_validate (nano::work_version::work_1, *epoch.get ()));
nano::process_result result (nano::process_result::old); nano::process_result result (nano::process_result::old);
if (valid_signature && valid_work) if (valid_signature && valid_work)
{ {
@ -2162,10 +2182,10 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
.balance (0) .balance (0)
.link (link) .link (link)
.sign (raw_key, signer) .sign (raw_key, signer)
.work (node_a->work_generate_blocking (key.account).value_or (0)) .work (node_a->work_generate_blocking (nano::work_version::work_1, key.account).value_or (0))
.build (); .build ();
bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ())); bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ()));
bool valid_work (!nano::work_validate (*epoch.get ())); bool valid_work (!nano::work_validate (nano::work_version::work_1, *epoch.get ()));
nano::process_result result (nano::process_result::old); nano::process_result result (nano::process_result::old);
if (valid_signature && valid_work) if (valid_signature && valid_work)
{ {
@ -3232,7 +3252,7 @@ void nano::json_handler::process ()
} }
if (!rpc_l->ec) if (!rpc_l->ec)
{ {
if (!nano::work_validate (*block)) if (!nano::work_validate (nano::work_version::work_1, *block))
{ {
auto result (rpc_l->node.process_local (block, watch_work_l)); auto result (rpc_l->node.process_local (block, watch_work_l));
switch (result.code) switch (result.code)
@ -3345,7 +3365,7 @@ void nano::json_handler::receive ()
{ {
head = account; head = account;
} }
if (nano::work_validate (head, work)) if (nano::work_validate (nano::work_version::work_1, head, work))
{ {
ec = nano::error_common::invalid_work; ec = nano::error_common::invalid_work;
} }
@ -3688,7 +3708,7 @@ void nano::json_handler::send ()
} }
if (!ec && work) if (!ec && work)
{ {
if (nano::work_validate (info.head, work)) if (nano::work_validate (nano::work_version::work_1, info.head, work))
{ {
ec = nano::error_common::invalid_work; ec = nano::error_common::invalid_work;
} }
@ -4895,7 +4915,9 @@ void nano::json_handler::work_generate ()
{ {
boost::optional<nano::account> account; boost::optional<nano::account> account;
auto account_opt (request.get_optional<std::string> ("account")); auto account_opt (request.get_optional<std::string> ("account"));
if (account_opt.is_initialized ()) // Default to work_1 if not specified
auto work_version (work_version_optional_impl (nano::work_version::work_1));
if (!ec && account_opt.is_initialized ())
{ {
account = account_impl (account_opt.get ()); account = account_impl (account_opt.get ());
} }
@ -4912,7 +4934,7 @@ void nano::json_handler::work_generate ()
{ {
auto use_peers (request.get<bool> ("use_peers", false)); auto use_peers (request.get<bool> ("use_peers", false));
auto rpc_l (shared_from_this ()); auto rpc_l (shared_from_this ());
auto callback = [rpc_l, hash, this](boost::optional<uint64_t> const & work_a) { auto callback = [rpc_l, hash, work_version, this](boost::optional<uint64_t> const & work_a) {
if (work_a) if (work_a)
{ {
boost::property_tree::ptree response_l; boost::property_tree::ptree response_l;
@ -4921,7 +4943,7 @@ void nano::json_handler::work_generate ()
response_l.put ("work", nano::to_string_hex (work)); response_l.put ("work", nano::to_string_hex (work));
std::stringstream ostream; std::stringstream ostream;
uint64_t result_difficulty; uint64_t result_difficulty;
nano::work_validate (hash, work, &result_difficulty); nano::work_validate (work_version, hash, work, &result_difficulty);
response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, this->node.network_params.network.publish_threshold); auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, this->node.network_params.network.publish_threshold);
response_l.put ("multiplier", nano::to_string (result_multiplier)); response_l.put ("multiplier", nano::to_string (result_multiplier));
@ -4937,7 +4959,7 @@ void nano::json_handler::work_generate ()
{ {
if (node.local_work_generation_enabled ()) if (node.local_work_generation_enabled ())
{ {
node.work.generate (hash, callback, difficulty); node.work.generate (work_version, hash, callback, difficulty);
} }
else else
{ {
@ -4959,7 +4981,7 @@ void nano::json_handler::work_generate ()
auto const & peers_l (secondary_work_peers_l ? node.config.secondary_work_peers : node.config.work_peers); auto const & peers_l (secondary_work_peers_l ? node.config.secondary_work_peers : node.config.work_peers);
if (node.work_generation_enabled (peers_l)) if (node.work_generation_enabled (peers_l))
{ {
node.work_generate (hash, callback, difficulty, account, secondary_work_peers_l); node.work_generate (work_version, hash, callback, difficulty, account, secondary_work_peers_l);
} }
else else
{ {
@ -5031,10 +5053,12 @@ void nano::json_handler::work_validate ()
auto work (work_optional_impl ()); auto work (work_optional_impl ());
auto difficulty (difficulty_optional_impl ()); auto difficulty (difficulty_optional_impl ());
multiplier_optional_impl (difficulty); multiplier_optional_impl (difficulty);
// Default to work_1 if not specified
auto work_version (work_version_optional_impl (nano::work_version::work_1));
if (!ec) if (!ec)
{ {
uint64_t result_difficulty (0); uint64_t result_difficulty (0);
nano::work_validate (hash, work, &result_difficulty); nano::work_validate (work_version, hash, work, &result_difficulty);
response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0"); response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0");
response_l.put ("difficulty", nano::to_string_hex (result_difficulty)); response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold); auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_threshold);

View file

@ -158,6 +158,7 @@ public:
uint64_t offset_optional_impl (uint64_t = 0); uint64_t offset_optional_impl (uint64_t = 0);
uint64_t difficulty_optional_impl (); uint64_t difficulty_optional_impl ();
double multiplier_optional_impl (uint64_t &); double multiplier_optional_impl (uint64_t &);
nano::work_version work_version_optional_impl (nano::work_version const default_a);
bool enable_sign_hash{ false }; bool enable_sign_hash{ false };
std::function<void()> stop_callback; std::function<void()> stop_callback;
nano::node_rpc_config const & node_rpc_config; nano::node_rpc_config const & node_rpc_config;

View file

@ -1006,14 +1006,14 @@ bool nano::node::work_generation_enabled (std::vector<std::pair<std::string, uin
return !peers_a.empty () || local_work_generation_enabled (); return !peers_a.empty () || local_work_generation_enabled ();
} }
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a) boost::optional<uint64_t> nano::node::work_generate_blocking (nano::work_version const version_a, nano::block & block_a)
{ {
return work_generate_blocking (block_a, network_params.network.publish_threshold); return work_generate_blocking (version_a, block_a, network_params.network.publish_threshold);
} }
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a, uint64_t difficulty_a) boost::optional<uint64_t> nano::node::work_generate_blocking (nano::work_version const version_a, nano::block & block_a, uint64_t difficulty_a)
{ {
auto opt_work_l (work_generate_blocking (block_a.root (), difficulty_a, block_a.account ())); auto opt_work_l (work_generate_blocking (version_a, block_a.root (), difficulty_a, block_a.account ()));
if (opt_work_l.is_initialized ()) if (opt_work_l.is_initialized ())
{ {
block_a.block_work_set (*opt_work_l); block_a.block_work_set (*opt_work_l);
@ -1021,37 +1021,61 @@ boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & bloc
return opt_work_l; return opt_work_l;
} }
void nano::node::work_generate (nano::root const & root_a, std::function<void(boost::optional<uint64_t>)> callback_a, boost::optional<nano::account> const & account_a) void nano::node::work_generate (nano::work_version const version_a, nano::root const & root_a, std::function<void(boost::optional<uint64_t>)> callback_a, boost::optional<nano::account> const & account_a)
{ {
work_generate (root_a, callback_a, network_params.network.publish_threshold, account_a); work_generate (version_a, root_a, callback_a, network_params.network.publish_threshold, account_a);
} }
void nano::node::work_generate (nano::root const & root_a, std::function<void(boost::optional<uint64_t>)> callback_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a, bool secondary_work_peers_a) void nano::node::work_generate (nano::work_version const version_a, nano::root const & root_a, std::function<void(boost::optional<uint64_t>)> callback_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a, bool secondary_work_peers_a)
{ {
auto const & peers_l (secondary_work_peers_a ? config.secondary_work_peers : config.work_peers); auto const & peers_l (secondary_work_peers_a ? config.secondary_work_peers : config.work_peers);
if (distributed_work.make (root_a, peers_l, callback_a, difficulty_a, account_a)) if (distributed_work.make (version_a, root_a, peers_l, callback_a, difficulty_a, account_a))
{ {
// Error in creating the job (either stopped or work generation is not possible) // Error in creating the job (either stopped or work generation is not possible)
callback_a (boost::none); callback_a (boost::none);
} }
} }
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::root const & root_a, boost::optional<nano::account> const & account_a) boost::optional<uint64_t> nano::node::work_generate_blocking (nano::work_version const version_a, nano::root const & root_a, boost::optional<nano::account> const & account_a)
{ {
return work_generate_blocking (root_a, network_params.network.publish_threshold, account_a); return work_generate_blocking (version_a, root_a, network_params.network.publish_threshold, account_a);
} }
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::root const & root_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a) boost::optional<uint64_t> nano::node::work_generate_blocking (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, boost::optional<nano::account> const & account_a)
{ {
std::promise<boost::optional<uint64_t>> promise; std::promise<boost::optional<uint64_t>> promise;
work_generate ( work_generate (
root_a, [&promise](boost::optional<uint64_t> opt_work_a) { version_a, root_a, [&promise](boost::optional<uint64_t> opt_work_a) {
promise.set_value (opt_work_a); promise.set_value (opt_work_a);
}, },
difficulty_a, account_a); difficulty_a, account_a);
return promise.get_future ().get (); return promise.get_future ().get ();
} }
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a)
{
assert (network_params.network.is_test_network ());
return work_generate_blocking (block_a, network_params.network.publish_threshold);
}
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a, uint64_t difficulty_a)
{
assert (network_params.network.is_test_network ());
return work_generate_blocking (nano::work_version::work_1, block_a, difficulty_a);
}
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::root const & root_a)
{
assert (network_params.network.is_test_network ());
return work_generate_blocking (root_a, network_params.network.publish_threshold);
}
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::root const & root_a, uint64_t difficulty_a)
{
assert (network_params.network.is_test_network ());
return work_generate_blocking (nano::work_version::work_1, root_a, difficulty_a);
}
void nano::node::add_initial_peers () void nano::node::add_initial_peers ()
{ {
auto transaction (store.tx_begin_read ()); auto transaction (store.tx_begin_read ());

View file

@ -129,12 +129,12 @@ public:
bool local_work_generation_enabled () const; bool local_work_generation_enabled () const;
bool work_generation_enabled () const; bool work_generation_enabled () const;
bool work_generation_enabled (std::vector<std::pair<std::string, uint16_t>> const &) const; bool work_generation_enabled (std::vector<std::pair<std::string, uint16_t>> const &) const;
boost::optional<uint64_t> work_generate_blocking (nano::block &, uint64_t); boost::optional<uint64_t> work_generate_blocking (nano::work_version const, nano::block &, uint64_t);
boost::optional<uint64_t> work_generate_blocking (nano::block &); boost::optional<uint64_t> work_generate_blocking (nano::work_version const, nano::block &);
boost::optional<uint64_t> work_generate_blocking (nano::root const &, uint64_t, boost::optional<nano::account> const & = boost::none); boost::optional<uint64_t> work_generate_blocking (nano::work_version const, nano::root const &, uint64_t, boost::optional<nano::account> const & = boost::none);
boost::optional<uint64_t> work_generate_blocking (nano::root const &, boost::optional<nano::account> const & = boost::none); boost::optional<uint64_t> work_generate_blocking (nano::work_version const, nano::root const &, boost::optional<nano::account> const & = boost::none);
void work_generate (nano::root const &, std::function<void(boost::optional<uint64_t>)>, uint64_t, boost::optional<nano::account> const & = boost::none, bool const = false); void work_generate (nano::work_version const, nano::root const &, std::function<void(boost::optional<uint64_t>)>, uint64_t, boost::optional<nano::account> const & = boost::none, bool const = false);
void work_generate (nano::root const &, std::function<void(boost::optional<uint64_t>)>, boost::optional<nano::account> const & = boost::none); void work_generate (nano::work_version const, nano::root const &, std::function<void(boost::optional<uint64_t>)>, boost::optional<nano::account> const & = boost::none);
void add_initial_peers (); void add_initial_peers ();
void block_confirm (std::shared_ptr<nano::block>); void block_confirm (std::shared_ptr<nano::block>);
bool block_confirmed_or_being_confirmed (nano::transaction const &, nano::block_hash const &); bool block_confirmed_or_being_confirmed (nano::transaction const &, nano::block_hash const &);
@ -195,6 +195,15 @@ public:
static double constexpr price_max = 16.0; static double constexpr price_max = 16.0;
static double constexpr free_cutoff = 1024.0; static double constexpr free_cutoff = 1024.0;
// For tests only
boost::optional<uint64_t> work_generate_blocking (nano::block &, uint64_t);
// For tests only
boost::optional<uint64_t> work_generate_blocking (nano::block &);
// For tests only
boost::optional<uint64_t> work_generate_blocking (nano::root const &, uint64_t);
// For tests only
boost::optional<uint64_t> work_generate_blocking (nano::root const &);
private: private:
void long_inactivity_cleanup (); void long_inactivity_cleanup ();
}; };

View file

@ -687,13 +687,13 @@ nano::opencl_work::~opencl_work ()
} }
} }
boost::optional<uint64_t> nano::opencl_work::generate_work (nano::root const & root_a, uint64_t const difficulty_a) boost::optional<uint64_t> nano::opencl_work::generate_work (nano::work_version const version_a, nano::root const & root_a, uint64_t const difficulty_a)
{ {
std::atomic<int> ticket_l{ 0 }; std::atomic<int> ticket_l{ 0 };
return generate_work (root_a, difficulty_a, ticket_l); return generate_work (version_a, root_a, difficulty_a, ticket_l);
} }
boost::optional<uint64_t> nano::opencl_work::generate_work (nano::root const & root_a, uint64_t const difficulty_a, std::atomic<int> & ticket_a) boost::optional<uint64_t> nano::opencl_work::generate_work (nano::work_version const version_a, nano::root const & root_a, uint64_t const difficulty_a, std::atomic<int> & ticket_a)
{ {
nano::lock_guard<std::mutex> lock (mutex); nano::lock_guard<std::mutex> lock (mutex);
bool error (false); bool error (false);
@ -702,7 +702,7 @@ boost::optional<uint64_t> nano::opencl_work::generate_work (nano::root const & r
uint64_t computed_difficulty (0); uint64_t computed_difficulty (0);
unsigned thread_count (config.threads); unsigned thread_count (config.threads);
size_t work_size[] = { thread_count, 0, 0 }; size_t work_size[] = { thread_count, 0, 0 };
while ((nano::work_validate (root_a, result, &computed_difficulty) || computed_difficulty < difficulty_a) && !error && ticket_a == ticket_l) while ((nano::work_validate (version_a, root_a, result, &computed_difficulty) || computed_difficulty < difficulty_a) && !error && ticket_a == ticket_l)
{ {
result = rand.next (); result = rand.next ();
cl_int write_error1 = clEnqueueWriteBuffer (queue, attempt_buffer, false, 0, sizeof (uint64_t), &result, 0, nullptr, nullptr); cl_int write_error1 = clEnqueueWriteBuffer (queue, attempt_buffer, false, 0, sizeof (uint64_t), &result, 0, nullptr, nullptr);

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <nano/lib/work.hpp>
#include <nano/node/openclconfig.hpp> #include <nano/node/openclconfig.hpp>
#include <nano/node/xorshift.hpp> #include <nano/node/xorshift.hpp>
@ -40,8 +41,8 @@ class opencl_work
public: public:
opencl_work (bool &, nano::opencl_config const &, nano::opencl_environment &, nano::logger_mt &); opencl_work (bool &, nano::opencl_config const &, nano::opencl_environment &, nano::logger_mt &);
~opencl_work (); ~opencl_work ();
boost::optional<uint64_t> generate_work (nano::root const &, uint64_t const); boost::optional<uint64_t> generate_work (nano::work_version const, nano::root const &, uint64_t const);
boost::optional<uint64_t> generate_work (nano::root const &, uint64_t const, std::atomic<int> &); boost::optional<uint64_t> generate_work (nano::work_version const, nano::root const &, uint64_t const, std::atomic<int> &);
static std::unique_ptr<opencl_work> create (bool, nano::opencl_config const &, nano::logger_mt &); static std::unique_ptr<opencl_work> create (bool, nano::opencl_config const &, nano::logger_mt &);
nano::opencl_config const & config; nano::opencl_config const & config;
std::mutex mutex; std::mutex mutex;

View file

@ -1134,10 +1134,10 @@ bool nano::wallet::action_complete (std::shared_ptr<nano::block> const & block_a
bool error{ false }; bool error{ false };
if (block_a != nullptr) if (block_a != nullptr)
{ {
if (nano::work_validate (*block_a)) if (nano::work_validate (nano::work_version::work_1, *block_a))
{ {
wallets.node.logger.try_log (boost::str (boost::format ("Cached or provided work for block %1% account %2% is invalid, regenerating") % block_a->hash ().to_string () % account_a.to_account ())); wallets.node.logger.try_log (boost::str (boost::format ("Cached or provided work for block %1% account %2% is invalid, regenerating") % block_a->hash ().to_string () % account_a.to_account ()));
error = !wallets.node.work_generate_blocking (*block_a, wallets.node.active.limited_active_difficulty ()).is_initialized (); error = !wallets.node.work_generate_blocking (nano::work_version::work_1, *block_a, wallets.node.active.limited_active_difficulty ()).is_initialized ();
} }
if (!error) if (!error)
{ {
@ -1217,7 +1217,7 @@ void nano::wallet::send_async (nano::account const & source_a, nano::account con
// Update work for account if latest root is root_a // Update work for account if latest root is root_a
void nano::wallet::work_update (nano::transaction const & transaction_a, nano::account const & account_a, nano::root const & root_a, uint64_t work_a) void nano::wallet::work_update (nano::transaction const & transaction_a, nano::account const & account_a, nano::root const & root_a, uint64_t work_a)
{ {
assert (!nano::work_validate (root_a, work_a)); assert (!nano::work_validate (nano::work_version::work_1, root_a, work_a));
assert (store.exists (transaction_a, account_a)); assert (store.exists (transaction_a, account_a));
auto block_transaction (wallets.node.store.tx_begin_read ()); auto block_transaction (wallets.node.store.tx_begin_read ());
auto latest (wallets.node.ledger.latest_root (block_transaction, account_a)); auto latest (wallets.node.ledger.latest_root (block_transaction, account_a));
@ -1364,7 +1364,7 @@ void nano::wallet::work_cache_blocking (nano::account const & account_a, nano::r
{ {
if (wallets.node.work_generation_enabled ()) if (wallets.node.work_generation_enabled ())
{ {
auto opt_work_l (wallets.node.work_generate_blocking (root_a, account_a)); auto opt_work_l (wallets.node.work_generate_blocking (nano::work_version::work_1, root_a, account_a));
if (opt_work_l.is_initialized ()) if (opt_work_l.is_initialized ())
{ {
auto transaction_l (wallets.tx_begin_write ()); auto transaction_l (wallets.tx_begin_write ());
@ -1401,7 +1401,7 @@ void nano::work_watcher::stop ()
stopped = true; stopped = true;
} }
void nano::work_watcher::add (std::shared_ptr<nano::block> block_a) void nano::work_watcher::add (std::shared_ptr<nano::block> block_a, nano::work_version const work_version_a)
{ {
auto block_l (std::dynamic_pointer_cast<nano::state_block> (block_a)); auto block_l (std::dynamic_pointer_cast<nano::state_block> (block_a));
if (!stopped && block_l != nullptr) if (!stopped && block_l != nullptr)
@ -1410,7 +1410,7 @@ void nano::work_watcher::add (std::shared_ptr<nano::block> block_a)
nano::unique_lock<std::mutex> lock (mutex); nano::unique_lock<std::mutex> lock (mutex);
watched[root_l] = block_l; watched[root_l] = block_l;
lock.unlock (); lock.unlock ();
watching (root_l, block_l); watching (work_version_a, root_l, block_l);
} }
} }
@ -1420,10 +1420,10 @@ void nano::work_watcher::update (nano::qualified_root const & root_a, std::share
watched[root_a] = block_a; watched[root_a] = block_a;
} }
void nano::work_watcher::watching (nano::qualified_root const & root_a, std::shared_ptr<nano::state_block> block_a) void nano::work_watcher::watching (nano::work_version const version_a, nano::qualified_root const & root_a, std::shared_ptr<nano::state_block> block_a)
{ {
std::weak_ptr<nano::work_watcher> watcher_w (shared_from_this ()); std::weak_ptr<nano::work_watcher> watcher_w (shared_from_this ());
node.alarm.add (std::chrono::steady_clock::now () + node.config.work_watcher_period, [block_a, root_a, watcher_w]() { node.alarm.add (std::chrono::steady_clock::now () + node.config.work_watcher_period, [block_a, version_a, root_a, watcher_w]() {
auto watcher_l = watcher_w.lock (); auto watcher_l = watcher_w.lock ();
if (watcher_l && !watcher_l->stopped && block_a != nullptr) if (watcher_l && !watcher_l->stopped && block_a != nullptr)
{ {
@ -1433,7 +1433,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
lock.unlock (); lock.unlock ();
uint64_t difficulty (0); uint64_t difficulty (0);
auto root_l (block_a->root ()); auto root_l (block_a->root ());
nano::work_validate (root_l, block_a->block_work (), &difficulty); nano::work_validate (version_a, root_l, block_a->block_work (), &difficulty);
auto active_difficulty (watcher_l->node.active.limited_active_difficulty ()); auto active_difficulty (watcher_l->node.active.limited_active_difficulty ());
/* /*
* Work watcher should still watch blocks even without work generation, although no rework is done * Work watcher should still watch blocks even without work generation, although no rework is done
@ -1442,7 +1442,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
if (active_difficulty > difficulty && watcher_l->node.work_generation_enabled ()) if (active_difficulty > difficulty && watcher_l->node.work_generation_enabled ())
{ {
watcher_l->node.work_generate ( watcher_l->node.work_generate (
root_l, [watcher_l, block_a, root_a](boost::optional<uint64_t> work_a) { version_a, root_l, [watcher_l, block_a, version_a, root_a](boost::optional<uint64_t> work_a) {
if (block_a != nullptr && watcher_l != nullptr && !watcher_l->stopped) if (block_a != nullptr && watcher_l != nullptr && !watcher_l->stopped)
{ {
bool updated_l{ false }; bool updated_l{ false };
@ -1457,12 +1457,12 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
watcher_l->node.active.update_difficulty (block); watcher_l->node.active.update_difficulty (block);
watcher_l->update (root_a, block); watcher_l->update (root_a, block);
updated_l = true; updated_l = true;
watcher_l->watching (root_a, block); watcher_l->watching (version_a, root_a, block);
} }
} }
if (!updated_l) if (!updated_l)
{ {
watcher_l->watching (root_a, block_a); watcher_l->watching (version_a, root_a, block_a);
} }
} }
}, },
@ -1470,7 +1470,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
} }
else else
{ {
watcher_l->watching (root_a, block_a); watcher_l->watching (version_a, root_a, block_a);
} }
} }
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <nano/lib/work.hpp>
#include <nano/node/lmdb/lmdb.hpp> #include <nano/node/lmdb/lmdb.hpp>
#include <nano/node/lmdb/wallet_value.hpp> #include <nano/node/lmdb/wallet_value.hpp>
#include <nano/node/openclwork.hpp> #include <nano/node/openclwork.hpp>
@ -10,7 +11,6 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <unordered_set> #include <unordered_set>
namespace nano namespace nano
{ {
class node; class node;
@ -168,9 +168,9 @@ public:
work_watcher (nano::node &); work_watcher (nano::node &);
~work_watcher (); ~work_watcher ();
void stop (); void stop ();
void add (std::shared_ptr<nano::block>); void add (std::shared_ptr<nano::block>, nano::work_version const);
void update (nano::qualified_root const &, std::shared_ptr<nano::state_block>); void update (nano::qualified_root const &, std::shared_ptr<nano::state_block>);
void watching (nano::qualified_root const &, std::shared_ptr<nano::state_block>); void watching (work_version const, nano::qualified_root const &, std::shared_ptr<nano::state_block>);
void remove (std::shared_ptr<nano::block>); void remove (std::shared_ptr<nano::block>);
bool is_watched (nano::qualified_root const &); bool is_watched (nano::qualified_root const &);
size_t size (); size_t size ();

View file

@ -773,7 +773,7 @@ nano::websocket::message nano::websocket::message_builder::difficulty_changed (u
return message_l; return message_l;
} }
nano::websocket::message nano::websocket::message_builder::work_generation (nano::block_hash const & root_a, uint64_t work_a, uint64_t difficulty_a, uint64_t publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector<std::string> const & bad_peers_a, bool completed_a, bool cancelled_a) nano::websocket::message nano::websocket::message_builder::work_generation (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t work_a, uint64_t difficulty_a, uint64_t publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector<std::string> const & bad_peers_a, bool completed_a, bool cancelled_a)
{ {
nano::websocket::message message_l (nano::websocket::topic::work); nano::websocket::message message_l (nano::websocket::topic::work);
set_common_fields (message_l); set_common_fields (message_l);
@ -785,6 +785,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano
work_l.put ("duration", duration_a.count ()); work_l.put ("duration", duration_a.count ());
boost::property_tree::ptree request_l; boost::property_tree::ptree request_l;
request_l.put ("version", nano::to_string (version_a));
request_l.put ("hash", root_a.to_string ()); request_l.put ("hash", root_a.to_string ());
request_l.put ("difficulty", nano::to_string_hex (difficulty_a)); request_l.put ("difficulty", nano::to_string_hex (difficulty_a));
auto request_multiplier_l (nano::difficulty::to_multiplier (difficulty_a, publish_threshold_a)); auto request_multiplier_l (nano::difficulty::to_multiplier (difficulty_a, publish_threshold_a));
@ -797,7 +798,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano
result_l.put ("source", peer_a); result_l.put ("source", peer_a);
result_l.put ("work", nano::to_string_hex (work_a)); result_l.put ("work", nano::to_string_hex (work_a));
uint64_t result_difficulty_l; uint64_t result_difficulty_l;
nano::work_validate (root_a, work_a, &result_difficulty_l); nano::work_validate (version_a, root_a, work_a, &result_difficulty_l);
result_l.put ("difficulty", nano::to_string_hex (result_difficulty_l)); result_l.put ("difficulty", nano::to_string_hex (result_difficulty_l));
auto result_multiplier_l (nano::difficulty::to_multiplier (result_difficulty_l, publish_threshold_a)); auto result_multiplier_l (nano::difficulty::to_multiplier (result_difficulty_l, publish_threshold_a));
result_l.put ("multiplier", nano::to_string (result_multiplier_l)); result_l.put ("multiplier", nano::to_string (result_multiplier_l));
@ -817,14 +818,14 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano
return message_l; return message_l;
} }
nano::websocket::message nano::websocket::message_builder::work_cancelled (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a) nano::websocket::message nano::websocket::message_builder::work_cancelled (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a)
{ {
return work_generation (root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, true); return work_generation (version_a, root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, true);
} }
nano::websocket::message nano::websocket::message_builder::work_failed (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a) nano::websocket::message nano::websocket::message_builder::work_failed (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a)
{ {
return work_generation (root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, false); return work_generation (version_a, root_a, 0, difficulty_a, publish_threshold_a, duration_a, "", bad_peers_a, false, false);
} }
nano::websocket::message nano::websocket::message_builder::bootstrap_started (std::string const & id_a, std::string const & mode_a) nano::websocket::message nano::websocket::message_builder::bootstrap_started (std::string const & id_a, std::string const & mode_a)

View file

@ -5,6 +5,7 @@
#include <nano/boost/beast/websocket.hpp> #include <nano/boost/beast/websocket.hpp>
#include <nano/lib/blocks.hpp> #include <nano/lib/blocks.hpp>
#include <nano/lib/numbers.hpp> #include <nano/lib/numbers.hpp>
#include <nano/lib/work.hpp>
#include <nano/secure/common.hpp> #include <nano/secure/common.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
@ -88,9 +89,10 @@ namespace websocket
message stopped_election (nano::block_hash const & hash_a); message stopped_election (nano::block_hash const & hash_a);
message vote_received (std::shared_ptr<nano::vote> vote_a, nano::vote_code code_a); message vote_received (std::shared_ptr<nano::vote> vote_a, nano::vote_code code_a);
message difficulty_changed (uint64_t publish_threshold_a, uint64_t difficulty_active_a); message difficulty_changed (uint64_t publish_threshold_a, uint64_t difficulty_active_a);
message work_generation (nano::block_hash const & root_a, uint64_t const work_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector<std::string> const & bad_peers_a, bool const completed_a = true, bool const cancelled_a = false);
message work_cancelled (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a); message work_generation (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const work_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::string const & peer_a, std::vector<std::string> const & bad_peers_a, bool const completed_a = true, bool const cancelled_a = false);
message work_failed (nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a); message work_cancelled (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a);
message work_failed (nano::work_version const version_a, nano::block_hash const & root_a, uint64_t const difficulty_a, uint64_t const publish_threshold_a, std::chrono::milliseconds const & duration_a, std::vector<std::string> const & bad_peers_a);
message bootstrap_started (std::string const & id_a, std::string const & mode_a); message bootstrap_started (std::string const & id_a, std::string const & mode_a);
message bootstrap_exited (std::string const & id_a, std::string const & mode_a, std::chrono::steady_clock::time_point const start_time_a, uint64_t const total_blocks_a); message bootstrap_exited (std::string const & id_a, std::string const & mode_a, std::chrono::steady_clock::time_point const start_time_a, uint64_t const total_blocks_a);

View file

@ -2229,7 +2229,7 @@ void nano_qt::block_creation::create_send ()
(void)error; (void)error;
assert (!error); assert (!error);
nano::state_block send (account_l, info.head, info.representative, balance - amount_l.number (), destination_l, key, account_l, 0); nano::state_block send (account_l, info.head, info.representative, balance - amount_l.number (), destination_l, key, account_l, 0);
if (wallet.node.work_generate_blocking (send).is_initialized ()) if (wallet.node.work_generate_blocking (nano::work_version::work_1, send).is_initialized ())
{ {
std::string block_l; std::string block_l;
send.serialize_json (block_l); send.serialize_json (block_l);
@ -2308,7 +2308,7 @@ void nano_qt::block_creation::create_receive ()
if (!error) if (!error)
{ {
nano::state_block receive (pending_key.account, info.head, info.representative, info.balance.number () + pending.amount.number (), source_l, key, pending_key.account, 0); nano::state_block receive (pending_key.account, info.head, info.representative, info.balance.number () + pending.amount.number (), source_l, key, pending_key.account, 0);
if (wallet.node.work_generate_blocking (receive).is_initialized ()) if (wallet.node.work_generate_blocking (nano::work_version::work_1, receive).is_initialized ())
{ {
std::string block_l; std::string block_l;
receive.serialize_json (block_l); receive.serialize_json (block_l);
@ -2387,7 +2387,7 @@ void nano_qt::block_creation::create_change ()
if (!error) if (!error)
{ {
nano::state_block change (account_l, info.head, representative_l, info.balance, 0, key, account_l, 0); nano::state_block change (account_l, info.head, representative_l, info.balance, 0, key, account_l, 0);
if (wallet.node.work_generate_blocking (change).is_initialized ()) if (wallet.node.work_generate_blocking (nano::work_version::work_1, change).is_initialized ())
{ {
std::string block_l; std::string block_l;
change.serialize_json (block_l); change.serialize_json (block_l);
@ -2464,7 +2464,7 @@ void nano_qt::block_creation::create_open ()
if (!error) if (!error)
{ {
nano::state_block open (pending_key.account, 0, representative_l, pending.amount, source_l, key, pending_key.account, 0); nano::state_block open (pending_key.account, 0, representative_l, pending.amount, source_l, key, pending_key.account, 0);
if (wallet.node.work_generate_blocking (open).is_initialized ()) if (wallet.node.work_generate_blocking (nano::work_version::work_1, open).is_initialized ())
{ {
std::string block_l; std::string block_l;
open.serialize_json (block_l); open.serialize_json (block_l);

View file

@ -3045,7 +3045,7 @@ TEST (rpc, work_peer_bad)
node2.config.work_peers.push_back (std::make_pair (boost::asio::ip::address_v6::any ().to_string (), 0)); node2.config.work_peers.push_back (std::make_pair (boost::asio::ip::address_v6::any ().to_string (), 0));
nano::block_hash hash1 (1); nano::block_hash hash1 (1);
std::atomic<uint64_t> work (0); std::atomic<uint64_t> work (0);
node2.work_generate (hash1, [&work](boost::optional<uint64_t> work_a) { node2.work_generate (nano::work_version::work_1, hash1, [&work](boost::optional<uint64_t> work_a) {
ASSERT_TRUE (work_a.is_initialized ()); ASSERT_TRUE (work_a.is_initialized ());
work = *work_a; work = *work_a;
}); });
@ -3075,7 +3075,7 @@ TEST (rpc, work_peer_one)
node2.config.work_peers.push_back (std::make_pair (node1.network.endpoint ().address ().to_string (), rpc.config.port)); node2.config.work_peers.push_back (std::make_pair (node1.network.endpoint ().address ().to_string (), rpc.config.port));
nano::keypair key1; nano::keypair key1;
uint64_t work (0); uint64_t work (0);
node2.work_generate (key1.pub, [&work](boost::optional<uint64_t> work_a) { node2.work_generate (nano::work_version::work_1, key1.pub, [&work](boost::optional<uint64_t> work_a) {
ASSERT_TRUE (work_a.is_initialized ()); ASSERT_TRUE (work_a.is_initialized ());
work = *work_a; work = *work_a;
}); });
@ -3122,7 +3122,7 @@ TEST (rpc, work_peer_many)
for (auto i (0); i < works.size (); ++i) for (auto i (0); i < works.size (); ++i)
{ {
nano::keypair key1; nano::keypair key1;
node1.work_generate (key1.pub, [& work = works[i]](boost::optional<uint64_t> work_a) { node1.work_generate (nano::work_version::work_1, key1.pub, [& work = works[i]](boost::optional<uint64_t> work_a) {
work = *work_a; work = *work_a;
}); });
while (nano::work_validate (key1.pub, works[i])) while (nano::work_validate (key1.pub, works[i]))
@ -3136,6 +3136,48 @@ TEST (rpc, work_peer_many)
node1.stop (); node1.stop ();
} }
TEST (rpc, work_version_invalid)
{
nano::system system;
auto node = add_ipc_enabled_node (system);
scoped_io_thread_name_change scoped_thread_name_io;
nano::node_rpc_config node_rpc_config;
nano::ipc::ipc_server ipc_server (*node, node_rpc_config);
nano::rpc_config rpc_config (nano::get_available_port (), true);
rpc_config.rpc_process.ipc_port = node->config.ipc_config.transport_tcp.port;
nano::ipc_rpc_processor ipc_rpc_processor (system.io_ctx, rpc_config);
nano::rpc rpc (system.io_ctx, rpc_config, ipc_rpc_processor);
rpc.start ();
nano::block_hash hash (1);
boost::property_tree::ptree request;
request.put ("action", "work_generate");
request.put ("hash", hash.to_string ());
request.put ("version", "work_invalid");
{
test_response response (request, rpc.config.port, system.io_ctx);
system.deadline_set (5s);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
ASSERT_EQ (1, response.json.count ("error"));
ASSERT_EQ (std::error_code (nano::error_rpc::bad_work_version).message (), response.json.get<std::string> ("error"));
}
request.put ("action", "work_validate");
{
test_response response (request, rpc.config.port, system.io_ctx);
system.deadline_set (5s);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (200, response.status);
ASSERT_EQ (1, response.json.count ("error"));
ASSERT_EQ (std::error_code (nano::error_rpc::bad_work_version).message (), response.json.get<std::string> ("error"));
}
}
TEST (rpc, block_count) TEST (rpc, block_count)
{ {
{ {

View file

@ -754,7 +754,7 @@ nano::uint128_t nano::ledger::account_pending (nano::transaction const & transac
nano::process_return nano::ledger::process (nano::write_transaction const & transaction_a, nano::block const & block_a, nano::signature_verification verification) nano::process_return nano::ledger::process (nano::write_transaction const & transaction_a, nano::block const & block_a, nano::signature_verification verification)
{ {
assert (!nano::work_validate (block_a)); assert (!nano::work_validate (nano::work_version::work_1, block_a));
ledger_processor processor (*this, transaction_a, verification); ledger_processor processor (*this, transaction_a, verification);
block_a.visit (processor); block_a.visit (processor);
if (processor.result.code == nano::process_result::progress) if (processor.result.code == nano::process_result::progress)