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:
parent
32b7f2a705
commit
8e03947f04
7 changed files with 90 additions and 41 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>);
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue