Difficulty extraction (#1401)

* Adding parameter to extract difficulty level out of a transaction.

* Allow difficulty level to be parameterized in work generation.

* Formatting.
This commit is contained in:
clemahieu 2018-11-20 09:06:12 -06:00 committed by GitHub
commit 8e03947f04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 41 deletions

View file

@ -54,7 +54,7 @@ TEST (message, publish_serialization)
ASSERT_EQ (rai::protocol_version, bytes[3]);
ASSERT_EQ (rai::protocol_version_min, bytes[4]);
ASSERT_EQ (static_cast<uint8_t> (rai::message_type::publish), bytes[5]);
ASSERT_EQ (0x00, bytes[6]); // extensions
ASSERT_EQ (0x00, bytes[6]); // extensions
ASSERT_EQ (static_cast<uint8_t> (rai::block_type::send), bytes[7]);
rai::bufferstream stream (bytes.data (), bytes.size ());
auto error (false);

View file

@ -8,16 +8,21 @@ TEST (work, one)
rai::work_pool pool (std::numeric_limits<unsigned>::max (), nullptr);
rai::change_block block (1, 1, rai::keypair ().prv, 3, 4);
block.block_work_set (pool.generate (block.root ()));
ASSERT_FALSE (rai::work_validate (block));
uint64_t difficulty;
ASSERT_FALSE (rai::work_validate (block, &difficulty));
ASSERT_LT (rai::work_pool::publish_threshold, difficulty);
}
TEST (work, validate)
{
rai::work_pool pool (std::numeric_limits<unsigned>::max (), nullptr);
rai::send_block send_block (1, 1, 2, rai::keypair ().prv, 4, 6);
ASSERT_TRUE (rai::work_validate (send_block));
uint64_t difficulty;
ASSERT_TRUE (rai::work_validate (send_block, &difficulty));
ASSERT_LT (difficulty, rai::work_pool::publish_threshold);
send_block.block_work_set (pool.generate (send_block.root ()));
ASSERT_FALSE (rai::work_validate (send_block));
ASSERT_FALSE (rai::work_validate (send_block, &difficulty));
ASSERT_LT (rai::work_pool::publish_threshold, difficulty);
}
TEST (work, cancel)
@ -91,3 +96,28 @@ TEST (work, opencl_config)
ASSERT_EQ (2, config2.device);
ASSERT_EQ (3, config2.threads);
}
TEST (work, difficulty)
{
rai::work_pool pool (std::numeric_limits<unsigned>::max (), nullptr);
rai::uint256_union root (1);
uint64_t difficulty1 (0xff00000000000000);
uint64_t difficulty2 (0xfff0000000000000);
uint64_t difficulty3 (0xffff000000000000);
uint64_t work1 (0);
uint64_t nonce1 (0);
do
{
work1 = pool.generate (root, difficulty1);
rai::work_validate (root, work1, &nonce1);
} while (nonce1 > difficulty2);
ASSERT_GT (nonce1, difficulty1);
uint64_t work2 (0);
uint64_t nonce2 (0);
do
{
work2 = pool.generate (root, difficulty2);
rai::work_validate (root, work2, &nonce2);
} while (nonce2 > difficulty3);
ASSERT_GT (nonce2, difficulty2);
}

View file

@ -5,14 +5,19 @@
#include <future>
bool rai::work_validate (rai::block_hash const & root_a, uint64_t work_a)
bool rai::work_validate (rai::block_hash const & root_a, uint64_t work_a, uint64_t * difficulty_a)
{
return rai::work_value (root_a, work_a) < rai::work_pool::publish_threshold;
auto value (rai::work_value (root_a, work_a));
if (difficulty_a != nullptr)
{
*difficulty_a = value;
}
return value < rai::work_pool::publish_threshold;
}
bool rai::work_validate (rai::block const & block_a)
bool rai::work_validate (rai::block const & block_a, uint64_t * difficulty_a)
{
return work_validate (block_a.root (), block_a.block_work ());
return work_validate (block_a.root (), block_a.block_work (), difficulty_a);
}
uint64_t rai::work_value (rai::block_hash const & root_a, uint64_t work_a)
@ -80,17 +85,17 @@ void rai::work_pool::loop (uint64_t thread)
lock.unlock ();
output = 0;
// ticket != ticket_l indicates a different thread found a solution and we should stop
while (ticket == ticket_l && output < rai::work_pool::publish_threshold)
while (ticket == ticket_l && output < current_l.difficulty)
{
// Don't query main memory every iteration in order to reduce memory bus traffic
// All operations here operate on stack memory
// Count iterations down to zero since comparing to zero is easier than comparing to another number
unsigned iteration (256);
while (iteration && output < rai::work_pool::publish_threshold)
while (iteration && output < current_l.difficulty)
{
work = rng.next ();
blake2b_update (&hash, reinterpret_cast<uint8_t *> (&work), sizeof (work));
blake2b_update (&hash, current_l.first.bytes.data (), current_l.first.bytes.size ());
blake2b_update (&hash, current_l.item.bytes.data (), current_l.item.bytes.size ());
blake2b_final (&hash, reinterpret_cast<uint8_t *> (&output), sizeof (output));
blake2b_init (&hash, sizeof (output));
iteration -= 1;
@ -101,12 +106,12 @@ void rai::work_pool::loop (uint64_t thread)
{
// If the ticket matches what we started with, we're the ones that found the solution
assert (output >= rai::work_pool::publish_threshold);
assert (work_value (current_l.first, work) == output);
assert (work_value (current_l.item, work) == output);
// Signal other threads to stop their work next time they check ticket
++ticket;
pending.pop_front ();
lock.unlock ();
current_l.second (work);
current_l.callback (work);
lock.lock ();
}
else
@ -127,16 +132,16 @@ void rai::work_pool::cancel (rai::uint256_union const & root_a)
std::lock_guard<std::mutex> lock (mutex);
if (!pending.empty ())
{
if (pending.front ().first == root_a)
if (pending.front ().item == root_a)
{
++ticket;
}
}
pending.remove_if ([&root_a](decltype (pending)::value_type const & item_a) {
bool result;
if (item_a.first == root_a)
if (item_a.item == root_a)
{
item_a.second (boost::none);
item_a.callback (boost::none);
result = true;
}
else
@ -154,7 +159,7 @@ void rai::work_pool::stop ()
producer_condition.notify_all ();
}
void rai::work_pool::generate (rai::uint256_union const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a)
void rai::work_pool::generate (rai::uint256_union const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a, uint64_t difficulty_a)
{
assert (!root_a.is_zero ());
boost::optional<uint64_t> result;
@ -165,7 +170,7 @@ void rai::work_pool::generate (rai::uint256_union const & root_a, std::function<
if (!result)
{
std::lock_guard<std::mutex> lock (mutex);
pending.push_back (std::make_pair (root_a, callback_a));
pending.push_back ({ root_a, callback_a, difficulty_a });
producer_condition.notify_all ();
}
else
@ -174,12 +179,13 @@ void rai::work_pool::generate (rai::uint256_union const & root_a, std::function<
}
}
uint64_t rai::work_pool::generate (rai::uint256_union const & hash_a)
uint64_t rai::work_pool::generate (rai::uint256_union const & hash_a, uint64_t difficulty_a)
{
std::promise<boost::optional<uint64_t>> work;
generate (hash_a, [&work](boost::optional<uint64_t> work_a) {
work.set_value (work_a);
});
},
difficulty_a);
auto result (work.get_future ().get ());
return result.value ();
}

View file

@ -14,10 +14,17 @@
namespace rai
{
class block;
bool work_validate (rai::block_hash const &, uint64_t);
bool work_validate (rai::block const &);
bool work_validate (rai::block_hash const &, uint64_t, uint64_t * = nullptr);
bool work_validate (rai::block const &, uint64_t * = nullptr);
uint64_t work_value (rai::block_hash const &, uint64_t);
class opencl_work;
class work_item
{
public:
rai::uint256_union item;
std::function<void(boost::optional<uint64_t> const &)> callback;
uint64_t difficulty;
};
class work_pool
{
public:
@ -26,12 +33,12 @@ public:
void loop (uint64_t);
void stop ();
void cancel (rai::uint256_union const &);
void generate (rai::uint256_union const &, std::function<void(boost::optional<uint64_t> const &)>);
uint64_t generate (rai::uint256_union const &);
void generate (rai::uint256_union const &, std::function<void(boost::optional<uint64_t> const &)>, uint64_t = rai::work_pool::publish_threshold);
uint64_t generate (rai::uint256_union const &, uint64_t = rai::work_pool::publish_threshold);
std::atomic<int> ticket;
bool done;
std::vector<boost::thread> threads;
std::list<std::pair<rai::uint256_union, std::function<void(boost::optional<uint64_t> const &)>>> pending;
std::list<rai::work_item> pending;
std::mutex mutex;
std::condition_variable producer_condition;
std::function<boost::optional<uint64_t> (rai::uint256_union const &)> opencl;

View file

@ -1999,17 +1999,18 @@ public:
class distributed_work : public std::enable_shared_from_this<distributed_work>
{
public:
distributed_work (std::shared_ptr<rai::node> const & node_a, rai::block_hash const & root_a, std::function<void(uint64_t)> callback_a) :
distributed_work (1, node_a, root_a, callback_a)
distributed_work (std::shared_ptr<rai::node> const & node_a, rai::block_hash const & root_a, std::function<void(uint64_t)> callback_a, uint64_t difficulty_a) :
distributed_work (1, node_a, root_a, callback_a, difficulty_a)
{
assert (node_a != nullptr);
}
distributed_work (unsigned int backoff_a, std::shared_ptr<rai::node> const & node_a, rai::block_hash const & root_a, std::function<void(uint64_t)> callback_a) :
distributed_work (unsigned int backoff_a, std::shared_ptr<rai::node> const & node_a, rai::block_hash const & root_a, std::function<void(uint64_t)> callback_a, uint64_t difficulty_a) :
callback (callback_a),
backoff (backoff_a),
node (node_a),
root (root_a),
need_resolve (node_a->config.work_peers)
need_resolve (node_a->config.work_peers),
difficulty (difficulty_a)
{
assert (node_a != nullptr);
completed.clear ();
@ -2214,7 +2215,8 @@ public:
auto callback_l (callback);
node->work.generate (root, [callback_l](boost::optional<uint64_t> const & work_a) {
callback_l (work_a.value ());
});
},
difficulty);
}
else
{
@ -2227,10 +2229,10 @@ public:
auto callback_l (callback);
std::weak_ptr<rai::node> node_w (node);
auto next_backoff (std::min (backoff * 2, (unsigned int)60 * 5));
node->alarm.add (now + std::chrono::seconds (backoff), [node_w, root_l, callback_l, next_backoff] {
node->alarm.add (now + std::chrono::seconds (backoff), [ node_w, root_l, callback_l, next_backoff, difficulty = difficulty ] {
if (auto node_l = node_w.lock ())
{
auto work_generation (std::make_shared<distributed_work> (next_backoff, node_l, root_l, callback_l));
auto work_generation (std::make_shared<distributed_work> (next_backoff, node_l, root_l, callback_l, difficulty));
work_generation->start ();
}
});
@ -2252,26 +2254,28 @@ public:
std::map<boost::asio::ip::address, uint16_t> outstanding;
std::vector<std::pair<std::string, uint16_t>> need_resolve;
std::atomic_flag completed;
uint64_t difficulty;
};
}
void rai::node::work_generate_blocking (rai::block & block_a)
void rai::node::work_generate_blocking (rai::block & block_a, uint64_t difficulty_a)
{
block_a.block_work_set (work_generate_blocking (block_a.root ()));
block_a.block_work_set (work_generate_blocking (block_a.root (), difficulty_a));
}
void rai::node::work_generate (rai::uint256_union const & hash_a, std::function<void(uint64_t)> callback_a)
void rai::node::work_generate (rai::uint256_union const & hash_a, std::function<void(uint64_t)> callback_a, uint64_t difficulty_a)
{
auto work_generation (std::make_shared<distributed_work> (shared (), hash_a, callback_a));
auto work_generation (std::make_shared<distributed_work> (shared (), hash_a, callback_a, difficulty_a));
work_generation->start ();
}
uint64_t rai::node::work_generate_blocking (rai::uint256_union const & hash_a)
uint64_t rai::node::work_generate_blocking (rai::uint256_union const & hash_a, uint64_t difficulty_a)
{
std::promise<uint64_t> promise;
work_generate (hash_a, [&promise](uint64_t work_a) {
promise.set_value (work_a);
});
},
difficulty_a);
return promise.get_future ().get ();
}

View file

@ -433,9 +433,9 @@ public:
void backup_wallet ();
void search_pending ();
int price (rai::uint128_t const &, int);
void work_generate_blocking (rai::block &);
uint64_t work_generate_blocking (rai::uint256_union const &);
void work_generate (rai::uint256_union const &, std::function<void(uint64_t)>);
void work_generate_blocking (rai::block &, uint64_t = rai::work_pool::publish_threshold);
uint64_t work_generate_blocking (rai::uint256_union const &, uint64_t = rai::work_pool::publish_threshold);
void work_generate (rai::uint256_union const &, std::function<void(uint64_t)>, uint64_t = rai::work_pool::publish_threshold);
void add_initial_peers ();
void block_confirm (std::shared_ptr<rai::block>);
void process_fork (rai::transaction const &, std::shared_ptr<rai::block>);

View file

@ -12,6 +12,8 @@
#include <future>
uint64_t const rai::work_pool::publish_threshold;
rai::uint256_union rai::wallet_store::check (rai::transaction const & transaction_a)
{
rai::wallet_value value (entry_get_raw (transaction_a, rai::wallet_store::check_special));