Handle epoch_2 work thresholds in the wallet and most RPCs (#2671)
* Handle epoch_2 work thresholds in most RPCs This PR is quite large with work generation and validation being a central piece of the node. In lib/config, work thresholds have been added for the beta and test network. They are now placed under a `nano::work_thresholds`. Unlike the main network, the thresholds are 2x and 1/2x from the base threshold. For tests, the previous base threshold was lowered such that the new highest difficulty (2x) is the same as before. The reason for this is that work generation targets the highest difficulty. `nano::work_validate` was renamed to `work_validate_entry`, further validation must be done by using `work_threshold_entry` and `work_threshold_full`. Work generation was changed to always require `difficulty`, except for tests. The reason is that any caller should not assume a base difficulty anymore. These RPCs now fully support the new thresholds and are ready for epoch_2 (will add some tests): - `process` validates at the minimum, entry difficulty, and handles the new `insufficient_work` result from ledger processing (used in https://github.com/nanocurrency/nano-node/pull/2667) - `send` and `account_representative_set` get the account epoch version and targets the correct difficulty - `receive` aditionally checks if the `source` epoch is higher, allowing new epoch propagation - `epoch_upgrader` These RPCs have changes to be compatible but are not yet optimal: - `block_create` now accepts an optional `difficulty`, and will generate at the highest difficulty otherwise (8x on mainnet). - `work_generate` also generates at the highest difficulty if `difficulty` is not specified, and multipliers are now off the highest difficulty. - `work_validate` validates at the highest difficulty unless `difficulty` is specified, meaning this is a breeaking change and it can return "not valid" for valid blocks. Multipliers are now off the highest difficulty. Support is also limited for active difficulty. It is currently calculated off the `epoch_1` difficulty to avoid any changes. All these cases will be handled in separate PRs, as this one is large enough as-is. * Define in source file * Fix websocket active_difficulty * Extract system::work_generate_limited * Fix debug_asserts in active_transactions::update_active_difficulty and add a test to ensure it * Add disabled test for RPC process, to be enabled in https://github.com/nanocurrency/nano-node/pull/2667 * Add auxiliary system::upgrade_genesis_epoch_2 * Set sideband block details for legacy blocks, unused for now * Higher amplitude between thresholds for the test network for easier testing * Handle work thresholds in the node wallet * Tests validating the node wallet handles thresholds * Final tests and adjustments * Fix ASSERT_NE * Add test ensuring the reduced work is also used when opening accounts previously upgraded * Ensure blocks from wallet meet the minimum difficulty * No need to change sideband for legacy, since the wallet never uses them * Enable test rpc.process_ledger_insufficient_work * Fix a couple of RPC tests being slow due to testing unrelated functionality
This commit is contained in:
parent
f875f303f7
commit
f9e6d8e818
34 changed files with 680 additions and 244 deletions
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace nano
|
||||
|
@ -147,12 +149,12 @@ TEST (active_transactions, adjusted_difficulty_priority)
|
|||
|
||||
//genesis and key1,key2 are opened
|
||||
//start chain of 2 on each
|
||||
auto send3 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send2->hash (), nano::test_genesis_key.pub, 9 * nano::xrb_ratio, key3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send2->hash (), nano::difficulty::from_multiplier (1500, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send4 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send3->hash (), nano::test_genesis_key.pub, 8 * nano::xrb_ratio, key3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send3->hash (), nano::difficulty::from_multiplier (1500, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send5 (std::make_shared<nano::state_block> (key1.pub, open1->hash (), key1.pub, 9 * nano::xrb_ratio, key3.pub, key1.prv, key1.pub, *system.work.generate (open1->hash (), nano::difficulty::from_multiplier (100, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send6 (std::make_shared<nano::state_block> (key1.pub, send5->hash (), key1.pub, 8 * nano::xrb_ratio, key3.pub, key1.prv, key1.pub, *system.work.generate (send5->hash (), nano::difficulty::from_multiplier (100, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send7 (std::make_shared<nano::state_block> (key2.pub, open2->hash (), key2.pub, 9 * nano::xrb_ratio, key3.pub, key2.prv, key2.pub, *system.work.generate (open2->hash (), nano::difficulty::from_multiplier (500, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send8 (std::make_shared<nano::state_block> (key2.pub, send7->hash (), key2.pub, 8 * nano::xrb_ratio, key3.pub, key2.prv, key2.pub, *system.work.generate (send7->hash (), nano::difficulty::from_multiplier (500, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send3 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send2->hash (), nano::test_genesis_key.pub, 9 * nano::xrb_ratio, key3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send2->hash (), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send4 (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, send3->hash (), nano::test_genesis_key.pub, 8 * nano::xrb_ratio, key3.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (send3->hash (), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send5 (std::make_shared<nano::state_block> (key1.pub, open1->hash (), key1.pub, 9 * nano::xrb_ratio, key3.pub, key1.prv, key1.pub, system.work_generate_limited (open1->hash (), nano::difficulty::from_multiplier (10, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send6 (std::make_shared<nano::state_block> (key1.pub, send5->hash (), key1.pub, 8 * nano::xrb_ratio, key3.pub, key1.prv, key1.pub, system.work_generate_limited (send5->hash (), nano::difficulty::from_multiplier (10, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send7 (std::make_shared<nano::state_block> (key2.pub, open2->hash (), key2.pub, 9 * nano::xrb_ratio, key3.pub, key2.prv, key2.pub, system.work_generate_limited (open2->hash (), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base))));
|
||||
auto send8 (std::make_shared<nano::state_block> (key2.pub, send7->hash (), key2.pub, 8 * nano::xrb_ratio, key3.pub, key2.prv, key2.pub, system.work_generate_limited (send7->hash (), nano::difficulty::from_multiplier (50, node1.network_params.network.publish_thresholds.base), nano::difficulty::from_multiplier (150, node1.network_params.network.publish_thresholds.base))));
|
||||
|
||||
node1.process_active (send3); // genesis
|
||||
node1.process_active (send5); // key1
|
||||
|
@ -894,3 +896,23 @@ TEST (active_transactions, insertion_prioritization)
|
|||
update_active_difficulty ();
|
||||
ASSERT_FALSE (node.active.insert (blocks[6]).prioritized);
|
||||
}
|
||||
|
||||
TEST (active_difficulty, less_than_one)
|
||||
{
|
||||
nano::system system (1);
|
||||
auto & node (*system.nodes[0]);
|
||||
nano::unique_lock<std::mutex> lock (node.active.mutex);
|
||||
auto base_active_difficulty = node.network_params.network.publish_thresholds.epoch_1;
|
||||
auto min_active_difficulty = node.network_params.network.publish_thresholds.entry;
|
||||
auto min_multiplier = nano::difficulty::to_multiplier (min_active_difficulty, base_active_difficulty);
|
||||
ASSERT_EQ (node.active.trended_active_difficulty, base_active_difficulty);
|
||||
for (int i = 0; i < node.active.multipliers_cb.size () - 1; ++i)
|
||||
{
|
||||
node.active.multipliers_cb.push_front (min_multiplier);
|
||||
}
|
||||
auto sum (std::accumulate (node.active.multipliers_cb.begin (), node.active.multipliers_cb.end (), double(0)));
|
||||
auto difficulty = nano::difficulty::from_multiplier (sum / node.active.multipliers_cb.size (), node.network_params.network.publish_thresholds.epoch_1);
|
||||
node.active.multipliers_cb.push_front (min_multiplier);
|
||||
node.active.update_active_difficulty (lock);
|
||||
ASSERT_EQ (node.active.trended_active_difficulty, difficulty);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,28 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/config.hpp>
|
||||
#include <nano/lib/epoch.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/node/testing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST (system, work_generate_limited)
|
||||
{
|
||||
nano::system system;
|
||||
nano::block_hash key (1);
|
||||
nano::network_constants constants;
|
||||
auto min = constants.publish_thresholds.entry;
|
||||
auto max = constants.publish_thresholds.base;
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
auto work = system.work_generate_limited (key, min, max);
|
||||
auto difficulty = nano::work_difficulty (nano::work_version::work_1, key, work);
|
||||
ASSERT_GE (difficulty, min);
|
||||
ASSERT_LT (difficulty, max);
|
||||
}
|
||||
}
|
||||
|
||||
TEST (difficulty, multipliers)
|
||||
{
|
||||
// For ASSERT_DEATH_IF_SUPPORTED
|
||||
|
@ -60,16 +80,6 @@ TEST (difficulty, multipliers)
|
|||
}
|
||||
}
|
||||
|
||||
TEST (difficulty, network_constants)
|
||||
{
|
||||
nano::network_constants constants;
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (constants.publish_full.epoch_2_receive, constants.publish_full.entry), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (constants.publish_full.epoch_2, constants.publish_full.base), 1e-10);
|
||||
ASSERT_NEAR (8., nano::difficulty::to_multiplier (constants.publish_full.epoch_2, constants.publish_full.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1 / 8., nano::difficulty::to_multiplier (constants.publish_full.epoch_2_receive, constants.publish_full.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1 / 64., nano::difficulty::to_multiplier (constants.publish_beta.base, constants.publish_full.epoch_1), 1e-10);
|
||||
}
|
||||
|
||||
TEST (difficulty, overflow)
|
||||
{
|
||||
// Overflow max (attempt to overflow & receive lower difficulty)
|
||||
|
@ -110,3 +120,44 @@ TEST (difficulty, zero)
|
|||
ASSERT_EQ (difficulty, nano::difficulty::from_multiplier (multiplier, base));
|
||||
}
|
||||
}
|
||||
|
||||
TEST (difficulty, network_constants)
|
||||
{
|
||||
nano::network_constants constants;
|
||||
auto & full_thresholds = constants.publish_full;
|
||||
auto & beta_thresholds = constants.publish_beta;
|
||||
auto & test_thresholds = constants.publish_test;
|
||||
|
||||
ASSERT_NEAR (8., nano::difficulty::to_multiplier (full_thresholds.epoch_2, full_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1 / 8., nano::difficulty::to_multiplier (full_thresholds.epoch_2_receive, full_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (full_thresholds.epoch_2_receive, full_thresholds.entry), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (full_thresholds.epoch_2, full_thresholds.base), 1e-10);
|
||||
|
||||
ASSERT_NEAR (1 / 64., nano::difficulty::to_multiplier (beta_thresholds.epoch_1, full_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (2., nano::difficulty::to_multiplier (beta_thresholds.epoch_2, beta_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1 / 2., nano::difficulty::to_multiplier (beta_thresholds.epoch_2_receive, beta_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (beta_thresholds.epoch_2_receive, beta_thresholds.entry), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (beta_thresholds.epoch_2, beta_thresholds.base), 1e-10);
|
||||
|
||||
ASSERT_NEAR (8., nano::difficulty::to_multiplier (test_thresholds.epoch_2, test_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1 / 8., nano::difficulty::to_multiplier (test_thresholds.epoch_2_receive, test_thresholds.epoch_1), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (test_thresholds.epoch_2_receive, test_thresholds.entry), 1e-10);
|
||||
ASSERT_NEAR (1., nano::difficulty::to_multiplier (test_thresholds.epoch_2, test_thresholds.base), 1e-10);
|
||||
|
||||
nano::work_version version{ nano::work_version::work_1 };
|
||||
ASSERT_EQ (constants.publish_thresholds.base, constants.publish_thresholds.epoch_2);
|
||||
ASSERT_EQ (constants.publish_thresholds.base, nano::work_threshold_base (version));
|
||||
ASSERT_EQ (constants.publish_thresholds.entry, nano::work_threshold_entry (version));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_0, false, false, false)));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_1, false, false, false)));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_1, false, false, false)));
|
||||
|
||||
// Send [+ change]
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_2, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_2, true, false, false)));
|
||||
// Change
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_2, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_2, false, false, false)));
|
||||
// Receive [+ change] / Open
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_2_receive, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_2, false, true, false)));
|
||||
// Epoch
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_2_receive, nano::work_threshold (version, nano::block_details (nano::epoch::epoch_2, false, false, true)));
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ TEST (distributed_work, stopped)
|
|||
{
|
||||
nano::system system (1);
|
||||
system.nodes[0]->distributed_work.stop ();
|
||||
ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::work_version::work_1, nano::block_hash (), {}, {}, nano::network_constants ().publish_test.base));
|
||||
ASSERT_TRUE (system.nodes[0]->distributed_work.make (nano::work_version::work_1, nano::block_hash (), {}, nano::network_constants ().publish_thresholds.base, {}));
|
||||
}
|
||||
|
||||
TEST (distributed_work, no_peers)
|
||||
|
@ -25,13 +25,13 @@ TEST (distributed_work, no_peers)
|
|||
work = work_a;
|
||||
done = true;
|
||||
};
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, node->network_params.network.publish_thresholds.base, callback, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, hash, *work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, hash, *work), node->network_params.network.publish_thresholds.base);
|
||||
// should only be removed after cleanup
|
||||
ASSERT_EQ (1, node->distributed_work.items.size ());
|
||||
while (!node->distributed_work.items.empty ())
|
||||
|
@ -47,7 +47,7 @@ TEST (distributed_work, no_peers_disabled)
|
|||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.work_threads = 0;
|
||||
auto & node = *system.add_node (node_config);
|
||||
ASSERT_TRUE (node.distributed_work.make (nano::work_version::work_1, nano::block_hash (), node.config.work_peers, {}, nano::network_constants ().publish_test.base));
|
||||
ASSERT_TRUE (node.distributed_work.make (nano::work_version::work_1, nano::block_hash (), node.config.work_peers, nano::network_constants ().publish_thresholds.base, {}));
|
||||
}
|
||||
|
||||
TEST (distributed_work, no_peers_cancel)
|
||||
|
@ -55,7 +55,7 @@ TEST (distributed_work, no_peers_cancel)
|
|||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.max_work_generate_multiplier = 1e6;
|
||||
node_config.max_work_generate_difficulty = nano::difficulty::from_multiplier (node_config.max_work_generate_multiplier, nano::network_constants ().publish_test.base);
|
||||
node_config.max_work_generate_difficulty = nano::difficulty::from_multiplier (node_config.max_work_generate_multiplier, nano::network_constants ().publish_thresholds.base);
|
||||
auto & node = *system.add_node (node_config);
|
||||
nano::block_hash hash{ 1 };
|
||||
bool done{ false };
|
||||
|
@ -63,7 +63,7 @@ TEST (distributed_work, no_peers_cancel)
|
|||
ASSERT_FALSE (work_a.is_initialized ());
|
||||
done = true;
|
||||
};
|
||||
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_thresholds.base)));
|
||||
ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_thresholds.base), callback_to_cancel));
|
||||
ASSERT_EQ (1, node.distributed_work.items.size ());
|
||||
// cleanup should not cancel or remove an ongoing work
|
||||
node.distributed_work.cleanup_finished ();
|
||||
|
@ -79,7 +79,7 @@ TEST (distributed_work, no_peers_cancel)
|
|||
|
||||
// now using observer
|
||||
done = false;
|
||||
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_thresholds.base)));
|
||||
ASSERT_FALSE (node.distributed_work.make (nano::work_version::work_1, hash, node.config.work_peers, nano::difficulty::from_multiplier (1e6, node.network_params.network.publish_thresholds.base), callback_to_cancel));
|
||||
ASSERT_EQ (1, node.distributed_work.items.size ());
|
||||
node.observers.work_cancel.notify (hash);
|
||||
system.deadline_set (20s);
|
||||
|
@ -103,7 +103,7 @@ TEST (distributed_work, no_peers_multi)
|
|||
// Test many works for the same root
|
||||
for (unsigned i{ 0 }; i < total; ++i)
|
||||
{
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, callback, nano::difficulty::from_multiplier (10, node->network_params.network.publish_thresholds.base)));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, node->config.work_peers, nano::difficulty::from_multiplier (10, node->network_params.network.publish_thresholds.base), callback));
|
||||
}
|
||||
// 1 root, and _total_ requests for that root are expected, but some may have already finished
|
||||
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)
|
||||
{
|
||||
nano::block_hash hash_i (i + 1);
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash_i, node->config.work_peers, callback, node->network_params.network.publish_thresholds.base));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash_i, node->config.work_peers, node->network_params.network.publish_thresholds.base, callback));
|
||||
}
|
||||
// 10 roots expected with 1 work each, but some may have completed so test for some
|
||||
ASSERT_GT (node->distributed_work.items.size (), 5);
|
||||
|
@ -171,13 +171,13 @@ TEST (distributed_work, peer)
|
|||
work_peer->start ();
|
||||
decltype (node->config.work_peers) peers;
|
||||
peers.emplace_back ("::ffff:127.0.0.1", work_peer->port ());
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, node->network_params.network.publish_thresholds.base, callback, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, hash, *work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, hash, *work), node->network_params.network.publish_thresholds.base);
|
||||
ASSERT_EQ (1, work_peer->generations_good);
|
||||
ASSERT_EQ (0, work_peer->generations_bad);
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
|
@ -201,13 +201,13 @@ TEST (distributed_work, peer_malicious)
|
|||
malicious_peer->start ();
|
||||
decltype (node->config.work_peers) peers;
|
||||
peers.emplace_back ("::ffff:127.0.0.1", malicious_peer->port ());
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, node->network_params.network.publish_thresholds.base, callback, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, hash, *work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, hash, *work), node->network_params.network.publish_thresholds.base);
|
||||
system.deadline_set (5s);
|
||||
while (malicious_peer->generations_bad < 1)
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ TEST (distributed_work, peer_malicious)
|
|||
auto malicious_peer2 (std::make_shared<fake_work_peer> (node->work, node->io_ctx, nano::get_available_port (), work_peer_type::malicious));
|
||||
malicious_peer2->start ();
|
||||
peers[0].second = malicious_peer2->port ();
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, nullptr, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, node->network_params.network.publish_thresholds.base, {}, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (malicious_peer2->generations_bad < 2)
|
||||
{
|
||||
|
@ -259,13 +259,13 @@ TEST (distributed_work, peer_multi)
|
|||
peers.emplace_back ("localhost", malicious_peer->port ());
|
||||
peers.emplace_back ("localhost", slow_peer->port ());
|
||||
peers.emplace_back ("localhost", good_peer->port ());
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, node->network_params.network.publish_thresholds.base, callback, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, hash, *work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, hash, *work), node->network_params.network.publish_thresholds.base);
|
||||
system.deadline_set (5s);
|
||||
while (slow_peer->cancels < 1)
|
||||
{
|
||||
|
@ -298,11 +298,11 @@ TEST (distributed_work, fail_resolve)
|
|||
};
|
||||
decltype (node->config.work_peers) peers;
|
||||
peers.emplace_back ("beeb.boop.123z", 0);
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, callback, node->network_params.network.publish_thresholds.base, nano::account ()));
|
||||
ASSERT_FALSE (node->distributed_work.make (nano::work_version::work_1, hash, peers, node->network_params.network.publish_thresholds.base, callback, nano::account ()));
|
||||
system.deadline_set (5s);
|
||||
while (!done)
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, hash, *work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, hash, *work), node->network_params.network.publish_thresholds.base);
|
||||
}
|
||||
|
|
|
@ -131,15 +131,16 @@ private:
|
|||
if (type == work_peer_type::good)
|
||||
{
|
||||
auto hash = hash_a;
|
||||
auto request_difficulty = nano::work_threshold_base (version);
|
||||
auto this_l (shared_from_this ());
|
||||
work_pool.generate (version, hash, [this_l, hash](boost::optional<uint64_t> work_a) {
|
||||
work_pool.generate (version, hash, request_difficulty, [this_l, hash](boost::optional<uint64_t> work_a) {
|
||||
auto result = work_a.value_or (0);
|
||||
auto difficulty (nano::work_difficulty (this_l->version, hash, result));
|
||||
auto result_difficulty (nano::work_difficulty (this_l->version, hash, result));
|
||||
static nano::network_params params;
|
||||
ptree::ptree message_l;
|
||||
message_l.put ("work", nano::to_string_hex (result));
|
||||
message_l.put ("difficulty", nano::to_string_hex (difficulty));
|
||||
message_l.put ("multiplier", nano::to_string (nano::difficulty::to_multiplier (difficulty, nano::work_threshold (this_l->version))));
|
||||
message_l.put ("difficulty", nano::to_string_hex (result_difficulty));
|
||||
message_l.put ("multiplier", nano::to_string (nano::difficulty::to_multiplier (result_difficulty, nano::work_threshold_base (this_l->version))));
|
||||
message_l.put ("hash", hash.to_string ());
|
||||
std::stringstream ostream;
|
||||
ptree::write_json (ostream, message_l);
|
||||
|
|
|
@ -28,6 +28,31 @@ TEST (node, stop)
|
|||
ASSERT_TRUE (true);
|
||||
}
|
||||
|
||||
TEST (node, work_generate)
|
||||
{
|
||||
nano::system system (1);
|
||||
auto & node (*system.nodes[0]);
|
||||
nano::block_hash root{ 1 };
|
||||
nano::work_version version{ nano::work_version::work_1 };
|
||||
{
|
||||
auto difficulty = nano::difficulty::from_multiplier (1.5, node.network_params.network.publish_thresholds.base);
|
||||
auto work = node.work_generate_blocking (version, root, difficulty);
|
||||
ASSERT_TRUE (work.is_initialized ());
|
||||
ASSERT_TRUE (nano::work_difficulty (version, root, *work) >= difficulty);
|
||||
}
|
||||
{
|
||||
auto difficulty = nano::difficulty::from_multiplier (0.5, node.network_params.network.publish_thresholds.base);
|
||||
boost::optional<uint64_t> work;
|
||||
do
|
||||
{
|
||||
work = node.work_generate_blocking (version, root, difficulty);
|
||||
} while (nano::work_difficulty (version, root, *work) >= node.network_params.network.publish_thresholds.base);
|
||||
ASSERT_TRUE (work.is_initialized ());
|
||||
ASSERT_TRUE (nano::work_difficulty (version, root, *work) >= difficulty);
|
||||
ASSERT_FALSE (nano::work_difficulty (version, root, *work) >= node.network_params.network.publish_thresholds.base);
|
||||
}
|
||||
}
|
||||
|
||||
TEST (node, block_store_path_failure)
|
||||
{
|
||||
auto service (boost::make_shared<boost::asio::io_context> ());
|
||||
|
@ -3732,10 +3757,10 @@ TEST (active_difficulty, recalculate_work)
|
|||
auto & node1 = *system.add_node (node_config);
|
||||
nano::genesis genesis;
|
||||
nano::keypair key1;
|
||||
ASSERT_EQ (node1.network_params.network.publish_thresholds.base, node1.active.active_difficulty ());
|
||||
ASSERT_EQ (node1.network_params.network.publish_thresholds.epoch_1, node1.active.active_difficulty ());
|
||||
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
|
||||
node1.work_generate_blocking (*send1);
|
||||
auto multiplier1 = nano::difficulty::to_multiplier (send1->difficulty (), nano::work_threshold (send1->work_version ()));
|
||||
auto multiplier1 = nano::difficulty::to_multiplier (send1->difficulty (), node1.network_params.network.publish_thresholds.epoch_1);
|
||||
// Process as local block
|
||||
node1.process_active (send1);
|
||||
system.deadline_set (2s);
|
||||
|
@ -3744,7 +3769,7 @@ TEST (active_difficulty, recalculate_work)
|
|||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
auto sum (std::accumulate (node1.active.multipliers_cb.begin (), node1.active.multipliers_cb.end (), double(0)));
|
||||
ASSERT_EQ (node1.active.active_difficulty (), nano::difficulty::from_multiplier (sum / node1.active.multipliers_cb.size (), node1.network_params.network.publish_thresholds.base));
|
||||
ASSERT_EQ (node1.active.active_difficulty (), nano::difficulty::from_multiplier (sum / node1.active.multipliers_cb.size (), node1.network_params.network.publish_thresholds.epoch_1));
|
||||
nano::unique_lock<std::mutex> lock (node1.active.mutex);
|
||||
// Fake history records to force work recalculation
|
||||
for (auto i (0); i < node1.active.multipliers_cb.size (); i++)
|
||||
|
@ -3755,7 +3780,7 @@ TEST (active_difficulty, recalculate_work)
|
|||
node1.process_active (send1);
|
||||
node1.active.update_active_difficulty (lock);
|
||||
sum = std::accumulate (node1.active.multipliers_cb.begin (), node1.active.multipliers_cb.end (), double(0));
|
||||
ASSERT_EQ (node1.active.trended_active_difficulty, nano::difficulty::from_multiplier (sum / node1.active.multipliers_cb.size (), node1.network_params.network.publish_thresholds.base));
|
||||
ASSERT_EQ (node1.active.trended_active_difficulty, nano::difficulty::from_multiplier (sum / node1.active.multipliers_cb.size (), node1.network_params.network.publish_thresholds.epoch_1));
|
||||
lock.unlock ();
|
||||
}
|
||||
|
||||
|
|
|
@ -649,7 +649,7 @@ TEST (wallet, work)
|
|||
uint64_t work (0);
|
||||
if (!wallet->store.work_get (transaction, nano::test_genesis_key.pub, work))
|
||||
{
|
||||
done = !nano::work_validate (genesis.open->work_version (), genesis.hash (), work);
|
||||
done = nano::work_difficulty (genesis.open->work_version (), genesis.hash (), work) >= nano::work_threshold_base (genesis.open->work_version ());
|
||||
}
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
|
@ -683,7 +683,7 @@ TEST (wallet, work_generate)
|
|||
ASSERT_NO_ERROR (system.poll ());
|
||||
auto block_transaction (node1.store.tx_begin_read ());
|
||||
auto transaction (system.wallet (0)->wallets.tx_begin_read ());
|
||||
again = wallet->store.work_get (transaction, account1, work1) || nano::work_validate (block->work_version (), node1.ledger.latest_root (block_transaction, account1), work1);
|
||||
again = wallet->store.work_get (transaction, account1, work1) || nano::work_difficulty (block->work_version (), node1.ledger.latest_root (block_transaction, account1), work1) < nano::work_threshold_base (block->work_version ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -949,7 +949,7 @@ TEST (wallet, no_work)
|
|||
auto block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key2.pub, std::numeric_limits<nano::uint128_t>::max (), false));
|
||||
ASSERT_NE (nullptr, block);
|
||||
ASSERT_NE (0, block->block_work ());
|
||||
ASSERT_FALSE (nano::work_validate (*block));
|
||||
ASSERT_GE (block->difficulty (), nano::work_threshold (block->work_version (), block->sideband ().details));
|
||||
auto transaction (system.wallet (0)->wallets.tx_begin_read ());
|
||||
uint64_t cached_work (0);
|
||||
system.wallet (0)->store.work_get (transaction, nano::test_genesis_key.pub, cached_work);
|
||||
|
@ -1185,7 +1185,7 @@ TEST (wallet, work_watcher_generation_disabled)
|
|||
node.wallets.watcher->add (block);
|
||||
ASSERT_FALSE (node.process_local (block).code != nano::process_result::progress);
|
||||
ASSERT_TRUE (node.wallets.watcher->is_watched (block->qualified_root ()));
|
||||
auto multiplier = nano::difficulty::to_multiplier (difficulty, nano::work_threshold (block->work_version ()));
|
||||
auto multiplier = nano::difficulty::to_multiplier (difficulty, nano::work_threshold_base (block->work_version ()));
|
||||
uint64_t updated_difficulty{ difficulty };
|
||||
{
|
||||
nano::unique_lock<std::mutex> lock (node.active.mutex);
|
||||
|
@ -1238,7 +1238,7 @@ TEST (wallet, work_watcher_cancel)
|
|||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.work_watcher_period = 1s;
|
||||
node_config.max_work_generate_multiplier = 1e6;
|
||||
node_config.max_work_generate_difficulty = nano::difficulty::from_multiplier (node_config.max_work_generate_multiplier, nano::network_constants ().publish_test.base);
|
||||
node_config.max_work_generate_difficulty = nano::difficulty::from_multiplier (node_config.max_work_generate_multiplier, nano::network_constants ().publish_thresholds.base);
|
||||
node_config.enable_voting = false;
|
||||
auto & node = *system.add_node (node_config);
|
||||
auto & wallet (*system.wallet (0));
|
||||
|
@ -1282,3 +1282,154 @@ TEST (wallet, work_watcher_cancel)
|
|||
ASSERT_TRUE (wallet.wallets.watcher->is_watched (block1->qualified_root ()));
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the minimum limited difficulty is enough for the highest threshold
|
||||
TEST (wallet, limited_difficulty)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.max_work_generate_difficulty = nano::network_constants ().publish_thresholds.base;
|
||||
nano::node_flags node_flags;
|
||||
node_flags.disable_request_loop = true;
|
||||
auto & node = *system.add_node (node_config, node_flags);
|
||||
auto & wallet (*system.wallet (0));
|
||||
// Upgrade the genesis account to epoch 2
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_1));
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_2));
|
||||
ASSERT_EQ (nano::epoch::epoch_2, node.store.block_version (node.store.tx_begin_read (), node.latest (nano::test_genesis_key.pub)));
|
||||
wallet.insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
{
|
||||
// Force active difficulty to an impossibly high value
|
||||
nano::lock_guard<std::mutex> guard (node.active.mutex);
|
||||
node.active.trended_active_difficulty = std::numeric_limits<uint64_t>::max ();
|
||||
}
|
||||
ASSERT_EQ (node_config.max_work_generate_difficulty, node.active.limited_active_difficulty ());
|
||||
auto send = wallet.send_action (nano::test_genesis_key.pub, nano::keypair ().pub, 1, 1);
|
||||
ASSERT_NE (nullptr, send);
|
||||
}
|
||||
|
||||
TEST (wallet, epoch_2_validation)
|
||||
{
|
||||
nano::system system (1);
|
||||
auto & node (*system.nodes[0]);
|
||||
auto & wallet (*system.wallet (0));
|
||||
|
||||
// Upgrade the genesis account to epoch 2
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_1));
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_2));
|
||||
|
||||
wallet.insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
|
||||
// Test send and receive blocks
|
||||
// An epoch 2 receive block should be generated with lower difficulty with high probability
|
||||
auto tries = 0;
|
||||
auto max_tries = 20;
|
||||
auto amount = node.config.receive_minimum.number ();
|
||||
while (++tries < max_tries)
|
||||
{
|
||||
auto send = wallet.send_action (nano::test_genesis_key.pub, nano::test_genesis_key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, send);
|
||||
|
||||
auto receive = wallet.receive_action (*send, nano::test_genesis_key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, receive);
|
||||
if (receive->difficulty () < node.network_params.network.publish_thresholds.base)
|
||||
{
|
||||
ASSERT_GE (receive->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_LT (tries, max_tries);
|
||||
|
||||
// Test a change block
|
||||
ASSERT_NE (nullptr, wallet.change_action (nano::test_genesis_key.pub, nano::keypair ().pub, 1));
|
||||
}
|
||||
|
||||
// Receiving from an upgraded account uses the lower threshold and upgrades the receiving account
|
||||
TEST (wallet, epoch_2_receive_propagation)
|
||||
{
|
||||
auto tries = 0;
|
||||
auto const max_tries = 20;
|
||||
while (++tries < max_tries)
|
||||
{
|
||||
nano::system system (1);
|
||||
auto & node (*system.nodes[0]);
|
||||
auto & wallet (*system.wallet (0));
|
||||
|
||||
// Upgrade the genesis account to epoch 1
|
||||
auto epoch1 = system.upgrade_genesis_epoch (node, nano::epoch::epoch_1);
|
||||
ASSERT_NE (nullptr, epoch1);
|
||||
|
||||
nano::keypair key;
|
||||
nano::state_block_builder builder;
|
||||
|
||||
// Send and open the account
|
||||
wallet.insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
wallet.insert_adhoc (key.prv, false);
|
||||
auto amount = node.config.receive_minimum.number ();
|
||||
auto send1 = wallet.send_action (nano::test_genesis_key.pub, key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, send1);
|
||||
ASSERT_NE (nullptr, wallet.receive_action (*send1, nano::test_genesis_key.pub, amount, 1));
|
||||
|
||||
// Upgrade the genesis account to epoch 2
|
||||
auto epoch2 = system.upgrade_genesis_epoch (node, nano::epoch::epoch_2);
|
||||
ASSERT_NE (nullptr, epoch2);
|
||||
|
||||
// Send a block
|
||||
auto send2 = wallet.send_action (nano::test_genesis_key.pub, key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, send2);
|
||||
|
||||
// Receiving should use the lower difficulty
|
||||
auto receive2 = wallet.receive_action (*send2, key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, receive2);
|
||||
if (receive2->difficulty () < node.network_params.network.publish_thresholds.base)
|
||||
{
|
||||
ASSERT_GE (receive2->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive);
|
||||
ASSERT_EQ (nano::epoch::epoch_2, node.store.block_version (node.store.tx_begin_read (), receive2->hash ()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_LT (tries, max_tries);
|
||||
}
|
||||
|
||||
// Opening an upgraded account uses the lower threshold
|
||||
TEST (wallet, epoch_2_receive_unopened)
|
||||
{
|
||||
// Ensure the lower receive work is used when receiving
|
||||
auto tries = 0;
|
||||
auto const max_tries = 20;
|
||||
while (++tries < max_tries)
|
||||
{
|
||||
nano::system system (1);
|
||||
auto & node (*system.nodes[0]);
|
||||
auto & wallet (*system.wallet (0));
|
||||
|
||||
// Upgrade the genesis account to epoch 1
|
||||
auto epoch1 = system.upgrade_genesis_epoch (node, nano::epoch::epoch_1);
|
||||
ASSERT_NE (nullptr, epoch1);
|
||||
|
||||
nano::keypair key;
|
||||
nano::state_block_builder builder;
|
||||
|
||||
// Send
|
||||
wallet.insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
auto amount = node.config.receive_minimum.number ();
|
||||
auto send1 = wallet.send_action (nano::test_genesis_key.pub, key.pub, amount, 1);
|
||||
|
||||
// Upgrade unopened account to epoch_2
|
||||
auto epoch2_unopened = nano::state_block (key.pub, 0, 0, 0, node.network_params.ledger.epochs.link (nano::epoch::epoch_2), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (key.pub, node.network_params.network.publish_thresholds.epoch_2));
|
||||
ASSERT_EQ (nano::process_result::progress, node.process (epoch2_unopened).code);
|
||||
|
||||
wallet.insert_adhoc (key.prv, false);
|
||||
|
||||
// Receiving should use the lower difficulty
|
||||
auto receive1 = wallet.receive_action (*send1, key.pub, amount, 1);
|
||||
ASSERT_NE (nullptr, receive1);
|
||||
if (receive1->difficulty () < node.network_params.network.publish_thresholds.base)
|
||||
{
|
||||
ASSERT_GE (receive1->difficulty (), node.network_params.network.publish_thresholds.epoch_2_receive);
|
||||
ASSERT_EQ (nano::epoch::epoch_2, node.store.block_version (node.store.tx_begin_read (), receive1->hash ()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_LT (tries, max_tries);
|
||||
}
|
||||
|
|
|
@ -104,14 +104,14 @@ TEST (websocket, active_difficulty)
|
|||
auto message_contents = event.get_child ("message");
|
||||
uint64_t network_minimum;
|
||||
nano::from_string_hex (message_contents.get<std::string> ("network_minimum"), network_minimum);
|
||||
ASSERT_EQ (network_minimum, node1->network_params.network.publish_thresholds.base);
|
||||
ASSERT_EQ (network_minimum, node1->network_params.network.publish_thresholds.epoch_1);
|
||||
|
||||
uint64_t network_current;
|
||||
nano::from_string_hex (message_contents.get<std::string> ("network_current"), network_current);
|
||||
ASSERT_EQ (network_current, node1->active.active_difficulty ());
|
||||
|
||||
double multiplier = message_contents.get<double> ("multiplier");
|
||||
ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (node1->active.active_difficulty (), node1->network_params.network.publish_thresholds.base), 1e-6);
|
||||
ASSERT_NEAR (multiplier, nano::difficulty::to_multiplier (node1->active.active_difficulty (), node1->network_params.network.publish_thresholds.epoch_1), 1e-6);
|
||||
}
|
||||
|
||||
// Subscribes to block confirmations, confirms a block and then awaits websocket notification
|
||||
|
|
|
@ -20,7 +20,7 @@ TEST (work, one)
|
|||
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
|
||||
nano::change_block block (1, 1, nano::keypair ().prv, 3, 4);
|
||||
block.block_work_set (*pool.generate (block.root ()));
|
||||
ASSERT_LT (nano::work_threshold (block.work_version ()), block.difficulty ());
|
||||
ASSERT_LT (nano::work_threshold_base (block.work_version ()), block.difficulty ());
|
||||
}
|
||||
|
||||
TEST (work, disabled)
|
||||
|
@ -36,9 +36,9 @@ TEST (work, validate)
|
|||
nano::network_constants network_constants;
|
||||
nano::work_pool pool (std::numeric_limits<unsigned>::max ());
|
||||
nano::send_block send_block (1, 1, 2, nano::keypair ().prv, 4, 6);
|
||||
ASSERT_LT (send_block.difficulty (), nano::work_threshold (send_block.work_version ()));
|
||||
ASSERT_LT (send_block.difficulty (), nano::work_threshold_base (send_block.work_version ()));
|
||||
send_block.block_work_set (*pool.generate (send_block.root ()));
|
||||
ASSERT_LT (nano::work_threshold (send_block.work_version ()), send_block.difficulty ());
|
||||
ASSERT_LT (nano::work_threshold_base (send_block.work_version ()), send_block.difficulty ());
|
||||
}
|
||||
|
||||
TEST (work, cancel)
|
||||
|
@ -49,7 +49,8 @@ TEST (work, cancel)
|
|||
while (!done)
|
||||
{
|
||||
nano::root key (1);
|
||||
pool.generate (key, [&done](boost::optional<uint64_t> work_a) {
|
||||
pool.generate (
|
||||
nano::work_version::work_1, key, nano::network_constants ().publish_thresholds.base, [&done](boost::optional<uint64_t> work_a) {
|
||||
done = !work_a;
|
||||
});
|
||||
pool.cancel (key);
|
||||
|
@ -67,12 +68,13 @@ TEST (work, cancel_many)
|
|||
nano::root key4 (1);
|
||||
nano::root key5 (3);
|
||||
nano::root key6 (1);
|
||||
pool.generate (key1, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (key2, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (key3, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (key4, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (key5, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (key6, [](boost::optional<uint64_t>) {});
|
||||
nano::network_constants constants;
|
||||
pool.generate (nano::work_version::work_1, key1, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (nano::work_version::work_1, key2, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (nano::work_version::work_1, key3, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (nano::work_version::work_1, key4, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (nano::work_version::work_1, key5, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.generate (nano::work_version::work_1, key6, constants.publish_thresholds.base, [](boost::optional<uint64_t>) {});
|
||||
pool.cancel (key1);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,14 +15,14 @@ work_thresholds const network_constants::publish_full (
|
|||
|
||||
work_thresholds const network_constants::publish_beta (
|
||||
0xfffff00000000000, // 64x lower than publish_full.epoch_1
|
||||
0xfffff00000000000,
|
||||
0xfffff00000000000 //
|
||||
0xfffff80000000000, // 2x higher than epoch_1
|
||||
0xffffe00000000000 // 2x lower than epoch_1
|
||||
);
|
||||
|
||||
work_thresholds const network_constants::publish_test (
|
||||
0xff00000000000000, // Very low for tests
|
||||
0xff00000000000000,
|
||||
0xff00000000000000 //
|
||||
0xfe00000000000000, // Very low for tests
|
||||
0xffc0000000000000, // 8x higher than epoch_1
|
||||
0xf000000000000000 // 8x lower than epoch_1
|
||||
);
|
||||
|
||||
const char * network_constants::active_network_err_msg = "Invalid network. Valid values are live, beta and test.";
|
||||
|
|
|
@ -244,6 +244,8 @@ std::string nano::error_process_messages::message (int ev) const
|
|||
return "Balance and amount delta do not match";
|
||||
case nano::error_process::block_position:
|
||||
return "This block cannot follow the previous block";
|
||||
case nano::error_process::insufficient_work:
|
||||
return "Block work is insufficient";
|
||||
case nano::error_process::other:
|
||||
return "Error processing block";
|
||||
}
|
||||
|
|
|
@ -135,6 +135,7 @@ enum class error_process
|
|||
opened_burn_account, // The impossible happened, someone found the private key associated with the public key '0'.
|
||||
balance_mismatch, // Balance and amount delta don't match
|
||||
block_position, // This block cannot follow the previous block
|
||||
insufficient_work, // Insufficient work for this block, even though it passed the minimal validation
|
||||
other
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/epoch.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/lib/work.hpp>
|
||||
#include <nano/node/xorshift.hpp>
|
||||
|
@ -21,14 +22,14 @@ std::string nano::to_string (nano::work_version const version_a)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool nano::work_validate (nano::block const & block_a)
|
||||
bool nano::work_validate_entry (nano::block const & block_a)
|
||||
{
|
||||
return block_a.difficulty () < nano::work_threshold (block_a.work_version ());
|
||||
return block_a.difficulty () < nano::work_threshold_entry (block_a.work_version ());
|
||||
}
|
||||
|
||||
bool nano::work_validate (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
|
||||
bool nano::work_validate_entry (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
|
||||
{
|
||||
return nano::work_difficulty (version_a, root_a, work_a) < nano::work_threshold (version_a);
|
||||
return nano::work_difficulty (version_a, root_a, work_a) < nano::work_threshold_entry (version_a);
|
||||
}
|
||||
|
||||
uint64_t nano::work_difficulty (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
|
||||
|
@ -45,16 +46,30 @@ uint64_t nano::work_difficulty (nano::work_version const version_a, nano::root c
|
|||
return result;
|
||||
}
|
||||
|
||||
uint64_t nano::work_threshold (nano::work_version const version_a)
|
||||
uint64_t nano::work_threshold_base (nano::work_version const version_a)
|
||||
{
|
||||
uint64_t result{ std::numeric_limits<uint64_t>::max () };
|
||||
switch (version_a)
|
||||
{
|
||||
case nano::work_version::work_1:
|
||||
result = nano::work_v1::threshold ();
|
||||
result = nano::work_v1::threshold_base ();
|
||||
break;
|
||||
default:
|
||||
debug_assert (false && "Invalid version specified to entry work_threshold");
|
||||
debug_assert (false && "Invalid version specified to work_threshold_base");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t nano::work_threshold_entry (nano::work_version const version_a)
|
||||
{
|
||||
uint64_t result{ std::numeric_limits<uint64_t>::max () };
|
||||
switch (version_a)
|
||||
{
|
||||
case nano::work_version::work_1:
|
||||
result = nano::work_v1::threshold_entry ();
|
||||
break;
|
||||
default:
|
||||
debug_assert (false && "Invalid version specified to work_threshold_entry");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -73,31 +88,32 @@ uint64_t nano::work_threshold (nano::work_version const version_a, nano::block_d
|
|||
return result;
|
||||
}
|
||||
|
||||
uint64_t nano::work_v1::threshold ()
|
||||
uint64_t nano::work_v1::threshold_base ()
|
||||
{
|
||||
static nano::network_constants network_constants;
|
||||
return network_constants.publish_thresholds.base;
|
||||
}
|
||||
|
||||
uint64_t nano::work_v1::threshold_entry ()
|
||||
{
|
||||
static nano::network_constants network_constants;
|
||||
return network_constants.publish_thresholds.entry;
|
||||
}
|
||||
|
||||
uint64_t nano::work_v1::threshold (nano::block_details const details_a)
|
||||
{
|
||||
static_assert (nano::epoch::max == nano::epoch::epoch_2, "work_v1::threshold is ill-defined");
|
||||
static nano::network_constants network_constants;
|
||||
|
||||
if (!network_constants.is_live_network ())
|
||||
{
|
||||
return network_constants.publish_thresholds.base;
|
||||
}
|
||||
|
||||
uint64_t result{ std::numeric_limits<uint64_t>::max () };
|
||||
switch (details_a.epoch)
|
||||
{
|
||||
case nano::epoch::epoch_2:
|
||||
result = (details_a.is_receive || details_a.is_epoch) ? network_constants.publish_full.epoch_2_receive : network_constants.publish_full.epoch_2;
|
||||
result = (details_a.is_receive || details_a.is_epoch) ? network_constants.publish_thresholds.epoch_2_receive : network_constants.publish_thresholds.epoch_2;
|
||||
break;
|
||||
case nano::epoch::epoch_1:
|
||||
case nano::epoch::epoch_0:
|
||||
result = network_constants.publish_full.epoch_1;
|
||||
result = network_constants.publish_thresholds.epoch_1;
|
||||
break;
|
||||
default:
|
||||
debug_assert (false && "Invalid epoch specified to work_v1 ledger work_threshold");
|
||||
|
@ -287,29 +303,14 @@ void nano::work_pool::stop ()
|
|||
producer_condition.notify_all ();
|
||||
}
|
||||
|
||||
void nano::work_pool::generate (nano::root const & root_a, std::function<void(boost::optional<uint64_t> const &)> callback_a)
|
||||
{
|
||||
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_thresholds.base);
|
||||
}
|
||||
|
||||
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)
|
||||
void nano::work_pool::generate (nano::work_version const version_a, nano::root const & root_a, uint64_t difficulty_a, std::function<void(boost::optional<uint64_t> const &)> callback_a)
|
||||
{
|
||||
debug_assert (!root_a.is_zero ());
|
||||
if (!threads.empty ())
|
||||
{
|
||||
{
|
||||
nano::lock_guard<std::mutex> lock (mutex);
|
||||
pending.emplace_back (version_a, root_a, callback_a, difficulty_a);
|
||||
pending.emplace_back (version_a, root_a, difficulty_a, callback_a);
|
||||
}
|
||||
producer_condition.notify_all ();
|
||||
}
|
||||
|
@ -323,12 +324,7 @@ boost::optional<uint64_t> nano::work_pool::generate (nano::root const & root_a)
|
|||
{
|
||||
static nano::network_constants network_constants;
|
||||
debug_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_thresholds.base);
|
||||
return generate (nano::work_version::work_1, root_a, network_constants.publish_thresholds.base);
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> nano::work_pool::generate (nano::root const & root_a, uint64_t difficulty_a)
|
||||
|
@ -345,11 +341,9 @@ boost::optional<uint64_t> nano::work_pool::generate (nano::work_version const ve
|
|||
{
|
||||
std::promise<boost::optional<uint64_t>> work;
|
||||
std::future<boost::optional<uint64_t>> future = work.get_future ();
|
||||
generate (
|
||||
version_a, root_a, [&work](boost::optional<uint64_t> work_a) {
|
||||
generate (version_a, root_a, difficulty_a, [&work](boost::optional<uint64_t> work_a) {
|
||||
work.set_value (work_a);
|
||||
},
|
||||
difficulty_a);
|
||||
});
|
||||
result = future.get ().value ();
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -22,33 +22,35 @@ std::string to_string (nano::work_version const version_a);
|
|||
|
||||
class block;
|
||||
class block_details;
|
||||
bool work_validate (nano::block const &);
|
||||
bool work_validate (nano::work_version const, nano::root const &, uint64_t const);
|
||||
bool work_validate_entry (nano::block const &);
|
||||
bool work_validate_entry (nano::work_version const, nano::root const &, uint64_t const);
|
||||
|
||||
uint64_t work_difficulty (nano::work_version const, nano::root const &, uint64_t const);
|
||||
// Entry threshold
|
||||
uint64_t work_threshold (nano::work_version const);
|
||||
|
||||
uint64_t work_threshold_base (nano::work_version const);
|
||||
uint64_t work_threshold_entry (nano::work_version const);
|
||||
// Ledger threshold
|
||||
uint64_t work_threshold (nano::work_version const, nano::block_details const);
|
||||
|
||||
namespace work_v1
|
||||
{
|
||||
uint64_t value (nano::root const & root_a, uint64_t work_a);
|
||||
uint64_t threshold ();
|
||||
uint64_t threshold_base ();
|
||||
uint64_t threshold_entry ();
|
||||
uint64_t threshold (nano::block_details const);
|
||||
}
|
||||
class opencl_work;
|
||||
class work_item final
|
||||
{
|
||||
public:
|
||||
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) :
|
||||
version (version_a), item (item_a), callback (callback_a), difficulty (difficulty_a)
|
||||
work_item (nano::work_version const version_a, nano::root const & item_a, uint64_t difficulty_a, std::function<void(boost::optional<uint64_t> const &)> const & callback_a) :
|
||||
version (version_a), item (item_a), difficulty (difficulty_a), callback (callback_a)
|
||||
{
|
||||
}
|
||||
nano::work_version version;
|
||||
nano::root item;
|
||||
std::function<void(boost::optional<uint64_t> const &)> callback;
|
||||
uint64_t difficulty;
|
||||
nano::work_version const version;
|
||||
nano::root const item;
|
||||
uint64_t const difficulty;
|
||||
std::function<void(boost::optional<uint64_t> const &)> const callback;
|
||||
};
|
||||
class work_pool final
|
||||
{
|
||||
|
@ -58,14 +60,9 @@ public:
|
|||
void loop (uint64_t);
|
||||
void stop ();
|
||||
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 &);
|
||||
void generate (nano::work_version const, nano::root const &, uint64_t, std::function<void(boost::optional<uint64_t> 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 &)>);
|
||||
// For tests only
|
||||
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 &, uint64_t);
|
||||
size_t size ();
|
||||
|
|
|
@ -188,8 +188,9 @@ int main (int argc, char * const * argv)
|
|||
<< "Public: " << rep.pub.to_string () << "\n"
|
||||
<< "Account: " << rep.pub.to_account () << "\n";
|
||||
}
|
||||
nano::network_constants network_constants;
|
||||
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 (nano::work_version::work_1, 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, network_constants.publish_thresholds.epoch_1));
|
||||
std::cout << genesis_block.to_json ();
|
||||
std::cout.flush ();
|
||||
nano::block_hash previous (genesis_block.hash ());
|
||||
|
@ -201,7 +202,7 @@ int main (int argc, char * const * argv)
|
|||
{
|
||||
debug_assert (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 (nano::work_version::work_1, previous));
|
||||
nano::send_block send (previous, landing.pub, balance, genesis.prv, genesis.pub, *work.generate (nano::work_version::work_1, previous, network_constants.publish_thresholds.epoch_1));
|
||||
previous = send.hash ();
|
||||
std::cout << send.to_json ();
|
||||
std::cout.flush ();
|
||||
|
@ -306,6 +307,8 @@ int main (int argc, char * const * argv)
|
|||
}
|
||||
else if (vm.count ("debug_profile_generate"))
|
||||
{
|
||||
nano::network_constants network_constants;
|
||||
uint64_t difficulty{ network_constants.publish_full.base };
|
||||
auto pow_rate_limiter = std::chrono::nanoseconds (0);
|
||||
auto pow_sleep_interval_it = vm.find ("pow_sleep_interval");
|
||||
if (pow_sleep_interval_it != vm.cend ())
|
||||
|
@ -320,7 +323,7 @@ int main (int argc, char * const * argv)
|
|||
{
|
||||
block.hashables.previous.qwords[0] += 1;
|
||||
auto begin1 (std::chrono::high_resolution_clock::now ());
|
||||
block.block_work_set (*work.generate (nano::work_version::work_1, block.root ()));
|
||||
block.block_work_set (*work.generate (nano::work_version::work_1, block.root (), difficulty));
|
||||
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 ());
|
||||
}
|
||||
|
@ -737,7 +740,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (genesis_balance)
|
||||
.link (keys[i].pub)
|
||||
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest))
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest, node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
genesis_latest = send->hash ();
|
||||
|
@ -750,7 +753,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (balances[i])
|
||||
.link (genesis_latest)
|
||||
.sign (keys[i].prv, keys[i].pub)
|
||||
.work (*work.generate (nano::work_version::work_1, keys[i].pub))
|
||||
.work (*work.generate (nano::work_version::work_1, keys[i].pub, node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
frontiers[i] = open->hash ();
|
||||
|
@ -771,7 +774,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (balances[j])
|
||||
.link (keys[other].pub)
|
||||
.sign (keys[j].prv, keys[j].pub)
|
||||
.work (*work.generate (nano::work_version::work_1, frontiers[j]))
|
||||
.work (*work.generate (nano::work_version::work_1, frontiers[j], node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
frontiers[j] = send->hash ();
|
||||
|
@ -786,7 +789,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (balances[other])
|
||||
.link (static_cast<nano::block_hash const &> (frontiers[j]))
|
||||
.sign (keys[other].prv, keys[other].pub)
|
||||
.work (*work.generate (nano::work_version::work_1, frontiers[other]))
|
||||
.work (*work.generate (nano::work_version::work_1, frontiers[other], node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
frontiers[other] = receive->hash ();
|
||||
|
@ -858,7 +861,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (genesis_balance)
|
||||
.link (keys[i].pub)
|
||||
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest))
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest, node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
genesis_latest = send->hash ();
|
||||
|
@ -871,7 +874,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (balance)
|
||||
.link (genesis_latest)
|
||||
.sign (keys[i].prv, keys[i].pub)
|
||||
.work (*work.generate (nano::work_version::work_1, keys[i].pub))
|
||||
.work (*work.generate (nano::work_version::work_1, keys[i].pub, node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
node->ledger.process (transaction, *open);
|
||||
|
@ -890,7 +893,7 @@ int main (int argc, char * const * argv)
|
|||
.balance (genesis_balance)
|
||||
.link (destination.pub)
|
||||
.sign (test_params.ledger.test_genesis_key.prv, test_params.ledger.test_genesis_key.pub)
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest))
|
||||
.work (*work.generate (nano::work_version::work_1, genesis_latest, node->network_params.network.publish_thresholds.epoch_1))
|
||||
.build ();
|
||||
|
||||
genesis_latest = send->hash ();
|
||||
|
@ -1104,7 +1107,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 ());
|
||||
}
|
||||
// Check if block work value is correct
|
||||
if (nano::work_validate (*block))
|
||||
if (block->difficulty () < nano::work_threshold (block->work_version (), block->sideband ().details))
|
||||
{
|
||||
std::cerr << boost::str (boost::format ("Invalid work for block %1% value: %2%\n") % hash.to_string () % nano::to_string_hex (block->block_work ()));
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ nano::active_transactions::active_transactions (nano::node & node_a, nano::confi
|
|||
confirmation_height_processor (confirmation_height_processor_a),
|
||||
node (node_a),
|
||||
multipliers_cb (20, 1.),
|
||||
trended_active_difficulty (node_a.network_params.network.publish_thresholds.base),
|
||||
trended_active_difficulty (node_a.network_params.network.publish_thresholds.epoch_1),
|
||||
check_all_elections_period (node_a.network_params.network.is_test_network () ? 10ms : 5s),
|
||||
election_time_to_live (node_a.network_params.network.is_test_network () ? 0s : 2s),
|
||||
prioritized_cutoff (std::max<size_t> (1, node_a.config.active_elections_size / 10)),
|
||||
|
@ -708,7 +708,7 @@ void nano::active_transactions::update_adjusted_difficulty ()
|
|||
auto existing_root (roots.get<tag_root> ().find (root));
|
||||
if (existing_root != roots.get<tag_root> ().end ())
|
||||
{
|
||||
sum += nano::difficulty::to_multiplier (existing_root->difficulty, node.network_params.network.publish_thresholds.base);
|
||||
sum += nano::difficulty::to_multiplier (existing_root->difficulty, node.network_params.network.publish_thresholds.epoch_1);
|
||||
elections_list.emplace_back (root, level);
|
||||
if (level > highest_level)
|
||||
{
|
||||
|
@ -726,7 +726,7 @@ void nano::active_transactions::update_adjusted_difficulty ()
|
|||
if (!elections_list.empty ())
|
||||
{
|
||||
double multiplier = sum / elections_list.size ();
|
||||
uint64_t average = nano::difficulty::from_multiplier (multiplier, node.network_params.network.publish_thresholds.base);
|
||||
uint64_t average = nano::difficulty::from_multiplier (multiplier, node.network_params.network.publish_thresholds.epoch_1);
|
||||
// Prevent overflow
|
||||
int64_t limiter (0);
|
||||
if (std::numeric_limits<std::uint64_t>::max () - average < static_cast<uint64_t> (highest_level))
|
||||
|
@ -778,18 +778,18 @@ void nano::active_transactions::update_active_difficulty (nano::unique_lock<std:
|
|||
}
|
||||
if (prioritized.size () > 10 || (node.network_params.network.is_test_network () && !prioritized.empty ()))
|
||||
{
|
||||
multiplier = nano::difficulty::to_multiplier (prioritized[prioritized.size () / 2], node.network_params.network.publish_thresholds.base);
|
||||
multiplier = nano::difficulty::to_multiplier (prioritized[prioritized.size () / 2], node.network_params.network.publish_thresholds.epoch_1);
|
||||
}
|
||||
if (!prioritized.empty ())
|
||||
{
|
||||
last_prioritized_difficulty = prioritized.back ();
|
||||
}
|
||||
}
|
||||
debug_assert (multiplier >= 1);
|
||||
debug_assert (multiplier >= nano::difficulty::to_multiplier (node.network_params.network.publish_thresholds.entry, node.network_params.network.publish_thresholds.epoch_1));
|
||||
multipliers_cb.push_front (multiplier);
|
||||
auto sum (std::accumulate (multipliers_cb.begin (), multipliers_cb.end (), double(0)));
|
||||
auto difficulty = nano::difficulty::from_multiplier (sum / multipliers_cb.size (), node.network_params.network.publish_thresholds.base);
|
||||
debug_assert (difficulty >= node.network_params.network.publish_thresholds.base);
|
||||
auto difficulty = nano::difficulty::from_multiplier (sum / multipliers_cb.size (), node.network_params.network.publish_thresholds.epoch_1);
|
||||
debug_assert (difficulty >= node.network_params.network.publish_thresholds.entry);
|
||||
|
||||
trended_active_difficulty = difficulty;
|
||||
node.observers.difficulty.notify (trended_active_difficulty);
|
||||
|
|
|
@ -85,7 +85,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)
|
||||
{
|
||||
debug_assert (!nano::work_validate (*info_a.block));
|
||||
debug_assert (!nano::work_validate_entry (*info_a.block));
|
||||
if (info_a.verified == nano::signature_verification::unknown && (info_a.block->type () == nano::block_type::state || info_a.block->type () == nano::block_type::open || !info_a.account.is_zero ()))
|
||||
{
|
||||
state_block_signature_verification.add (info_a);
|
||||
|
|
|
@ -213,7 +213,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
|
|||
{
|
||||
nano::bufferstream stream (connection->receive_buffer->data (), size_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_entry (*block))
|
||||
{
|
||||
auto hash (block->hash ());
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
|
|
|
@ -232,7 +232,7 @@ void nano::bulk_push_server::received_block (boost::system::error_code const & e
|
|||
{
|
||||
nano::bufferstream stream (receive_buffer->data (), size_a);
|
||||
auto block (nano::deserialize_block (stream, type_a));
|
||||
if (block != nullptr && !nano::work_validate (*block))
|
||||
if (block != nullptr && !nano::work_validate_entry (*block))
|
||||
{
|
||||
connection->node->process_active (std::move (block));
|
||||
throttled_receive ();
|
||||
|
|
|
@ -431,7 +431,7 @@ void nano::message_parser::deserialize_publish (nano::stream & stream_a, nano::m
|
|||
nano::publish incoming (error, stream_a, header_a, digest_a, &block_uniquer);
|
||||
if (!error && at_end (stream_a))
|
||||
{
|
||||
if (!nano::work_validate (*incoming.block))
|
||||
if (!nano::work_validate_entry (*incoming.block))
|
||||
{
|
||||
visitor.publish (incoming);
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ void nano::message_parser::deserialize_confirm_req (nano::stream & stream_a, nan
|
|||
nano::confirm_req incoming (error, stream_a, header_a, &block_uniquer);
|
||||
if (!error && at_end (stream_a))
|
||||
{
|
||||
if (incoming.block == nullptr || !nano::work_validate (*incoming.block))
|
||||
if (incoming.block == nullptr || !nano::work_validate_entry (*incoming.block))
|
||||
{
|
||||
visitor.confirm_req (incoming);
|
||||
}
|
||||
|
@ -478,7 +478,7 @@ void nano::message_parser::deserialize_confirm_ack (nano::stream & stream_a, nan
|
|||
if (!vote_block.which ())
|
||||
{
|
||||
auto block (boost::get<std::shared_ptr<nano::block>> (vote_block));
|
||||
if (nano::work_validate (*block))
|
||||
if (nano::work_validate_entry (*block))
|
||||
{
|
||||
status = parse_status::insufficient_work;
|
||||
break;
|
||||
|
|
|
@ -107,8 +107,7 @@ void nano::distributed_work::start_local ()
|
|||
{
|
||||
auto this_l (shared_from_this ());
|
||||
local_generation_started = true;
|
||||
node.work.generate (
|
||||
request.version, request.root, [this_l](boost::optional<uint64_t> const & work_a) {
|
||||
node.work.generate (request.version, request.root, request.difficulty, [this_l](boost::optional<uint64_t> const & work_a) {
|
||||
if (work_a.is_initialized ())
|
||||
{
|
||||
this_l->set_once (*work_a);
|
||||
|
@ -122,8 +121,7 @@ void nano::distributed_work::start_local ()
|
|||
}
|
||||
}
|
||||
this_l->stop_once (false);
|
||||
},
|
||||
request.difficulty);
|
||||
});
|
||||
}
|
||||
|
||||
void nano::distributed_work::do_request (nano::tcp_endpoint const & endpoint_a)
|
||||
|
@ -323,7 +321,7 @@ void nano::distributed_work::set_once (uint64_t const work_a, std::string const
|
|||
if (node.config.logging.work_generation_time ())
|
||||
{
|
||||
boost::format unformatted_l ("Work generation for %1%, with a threshold difficulty of %2% (multiplier %3%x) complete: %4% ms");
|
||||
auto multiplier_text_l (nano::to_string (nano::difficulty::to_multiplier (request.difficulty, nano::work_threshold (request.version)), 2));
|
||||
auto multiplier_text_l (nano::to_string (nano::difficulty::to_multiplier (request.difficulty, node.network_params.network.publish_thresholds.base), 2));
|
||||
node.logger.try_log (boost::str (unformatted_l % request.root.to_string () % nano::to_string_hex (request.difficulty) % multiplier_text_l % elapsed.value ().count ()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ nano::distributed_work_factory::~distributed_work_factory ()
|
|||
stop ();
|
||||
}
|
||||
|
||||
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)
|
||||
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, uint64_t difficulty_a, std::function<void(boost::optional<uint64_t>)> const & callback_a, boost::optional<nano::account> const & account_a)
|
||||
{
|
||||
return make (std::chrono::seconds (1), nano::work_request{ version_a, root_a, difficulty_a, account_a, callback_a, peers_a });
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class distributed_work_factory final
|
|||
public:
|
||||
distributed_work_factory (nano::node &);
|
||||
~distributed_work_factory ();
|
||||
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 (nano::work_version const, nano::root const &, std::vector<std::pair<std::string, uint16_t>> const &, uint64_t, std::function<void(boost::optional<uint64_t>)> const &, boost::optional<nano::account> const & = boost::none);
|
||||
bool make (std::chrono::seconds const &, nano::work_request const &);
|
||||
void cancel (nano::root const &, bool const local_stop = false);
|
||||
void cleanup_finished ();
|
||||
|
|
|
@ -716,7 +716,8 @@ void nano::json_handler::account_representative_set ()
|
|||
auto info (rpc_l->account_info_impl (block_transaction, account));
|
||||
if (!rpc_l->ec)
|
||||
{
|
||||
if (nano::work_validate (nano::work_version::work_1, info.head, work))
|
||||
nano::block_details details (info.epoch (), false, false, false);
|
||||
if (nano::work_difficulty (nano::work_version::work_1, info.head, work) < nano::work_threshold (nano::work_version::work_1, details))
|
||||
{
|
||||
rpc_l->ec = nano::error_common::invalid_work;
|
||||
}
|
||||
|
@ -909,10 +910,10 @@ void nano::json_handler::accounts_pending ()
|
|||
void nano::json_handler::active_difficulty ()
|
||||
{
|
||||
auto include_trend (request.get<bool> ("include_trend", false));
|
||||
response_l.put ("network_minimum", nano::to_string_hex (node.network_params.network.publish_thresholds.base));
|
||||
response_l.put ("network_minimum", nano::to_string_hex (node.network_params.network.publish_thresholds.epoch_1));
|
||||
auto difficulty_active = node.active.active_difficulty ();
|
||||
response_l.put ("network_current", nano::to_string_hex (difficulty_active));
|
||||
auto multiplier = nano::difficulty::to_multiplier (difficulty_active, node.network_params.network.publish_thresholds.base);
|
||||
auto multiplier = nano::difficulty::to_multiplier (difficulty_active, node.network_params.network.publish_thresholds.epoch_1);
|
||||
response_l.put ("multiplier", nano::to_string (multiplier));
|
||||
if (include_trend)
|
||||
{
|
||||
|
@ -1247,8 +1248,9 @@ void nano::json_handler::block_create ()
|
|||
{
|
||||
std::string type (request.get<std::string> ("type"));
|
||||
nano::wallet_id wallet (0);
|
||||
auto difficulty_l (difficulty_optional_impl ());
|
||||
boost::optional<std::string> wallet_text (request.get_optional<std::string> ("wallet"));
|
||||
if (wallet_text.is_initialized ())
|
||||
if (!ec && wallet_text.is_initialized ())
|
||||
{
|
||||
if (wallet.decode_hex (wallet_text.get ()))
|
||||
{
|
||||
|
@ -1559,7 +1561,7 @@ void nano::json_handler::block_create ()
|
|||
{
|
||||
if (work == 0)
|
||||
{
|
||||
node.work_generate (work_version, root_l, get_callback_l (block_l), nano::account (pub));
|
||||
node.work_generate (work_version, root_l, difficulty_l, get_callback_l (block_l), nano::account (pub));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2120,6 +2122,7 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
|
|||
nano::account_info info;
|
||||
if (!node_a->store.account_get (transaction, i->account, info) && info.epoch () < epoch_a)
|
||||
{
|
||||
auto difficulty (nano::work_threshold (nano::work_version::work_1, nano::block_details (epoch_a, false, false, true)));
|
||||
auto epoch = builder.state ()
|
||||
.account (i->account)
|
||||
.previous (info.head)
|
||||
|
@ -2127,10 +2130,10 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
|
|||
.balance (info.balance)
|
||||
.link (link)
|
||||
.sign (raw_key, signer)
|
||||
.work (node_a->work_generate_blocking (nano::work_version::work_1, info.head).value_or (0))
|
||||
.work (node_a->work_generate_blocking (nano::work_version::work_1, info.head, difficulty).value_or (0))
|
||||
.build ();
|
||||
bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ()));
|
||||
bool valid_work (!nano::work_validate (*epoch.get ()));
|
||||
bool valid_work (epoch->difficulty () >= difficulty);
|
||||
nano::process_result result (nano::process_result::old);
|
||||
if (valid_signature && valid_work)
|
||||
{
|
||||
|
@ -2179,6 +2182,7 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
|
|||
if (info.epoch < epoch_a)
|
||||
{
|
||||
release_assert (nano::epochs::is_sequential (info.epoch, epoch_a));
|
||||
auto difficulty (nano::work_threshold (nano::work_version::work_1, nano::block_details (epoch_a, false, false, true)));
|
||||
auto epoch = builder.state ()
|
||||
.account (key.account)
|
||||
.previous (0)
|
||||
|
@ -2186,10 +2190,10 @@ void epoch_upgrader (std::shared_ptr<nano::node> node_a, nano::private_key const
|
|||
.balance (0)
|
||||
.link (link)
|
||||
.sign (raw_key, signer)
|
||||
.work (node_a->work_generate_blocking (nano::work_version::work_1, key.account).value_or (0))
|
||||
.work (node_a->work_generate_blocking (nano::work_version::work_1, key.account, difficulty).value_or (0))
|
||||
.build ();
|
||||
bool valid_signature (!nano::validate_message (signer, epoch->hash (), epoch->block_signature ()));
|
||||
bool valid_work (!nano::work_validate (*epoch.get ()));
|
||||
bool valid_work (epoch->difficulty () >= difficulty);
|
||||
nano::process_result result (nano::process_result::old);
|
||||
if (valid_signature && valid_work)
|
||||
{
|
||||
|
@ -3255,7 +3259,7 @@ void nano::json_handler::process ()
|
|||
}
|
||||
if (!rpc_l->ec)
|
||||
{
|
||||
if (!nano::work_validate (*block))
|
||||
if (!nano::work_validate_entry (*block))
|
||||
{
|
||||
auto result (rpc_l->node.process_local (block, watch_work_l));
|
||||
switch (result.code)
|
||||
|
@ -3321,6 +3325,11 @@ void nano::json_handler::process ()
|
|||
}
|
||||
break;
|
||||
}
|
||||
case nano::process_result::insufficient_work:
|
||||
{
|
||||
rpc_l->ec = nano::error_process::insufficient_work;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
rpc_l->ec = nano::error_process::other;
|
||||
|
@ -3360,15 +3369,19 @@ void nano::json_handler::receive ()
|
|||
{
|
||||
nano::account_info info;
|
||||
nano::root head;
|
||||
nano::epoch epoch = block->sideband ().details.epoch;
|
||||
if (!node.store.account_get (block_transaction, account, info))
|
||||
{
|
||||
head = info.head;
|
||||
// When receiving, epoch version is the higher between the previous and the source blocks
|
||||
epoch = std::max (info.epoch (), epoch);
|
||||
}
|
||||
else
|
||||
{
|
||||
head = account;
|
||||
}
|
||||
if (nano::work_validate (nano::work_version::work_1, head, work))
|
||||
nano::block_details details (epoch, false, true, false);
|
||||
if (nano::work_difficulty (nano::work_version::work_1, head, work) < nano::work_threshold (nano::work_version::work_1, details))
|
||||
{
|
||||
ec = nano::error_common::invalid_work;
|
||||
}
|
||||
|
@ -3711,7 +3724,8 @@ void nano::json_handler::send ()
|
|||
}
|
||||
if (!ec && work)
|
||||
{
|
||||
if (nano::work_validate (nano::work_version::work_1, info.head, work))
|
||||
nano::block_details details (info.epoch (), true, false, false);
|
||||
if (nano::work_difficulty (nano::work_version::work_1, info.head, work) < nano::work_threshold (nano::work_version::work_1, details))
|
||||
{
|
||||
ec = nano::error_common::invalid_work;
|
||||
}
|
||||
|
@ -4938,7 +4952,7 @@ void nano::json_handler::work_generate ()
|
|||
auto hash (hash_impl ());
|
||||
auto difficulty (difficulty_optional_impl ());
|
||||
multiplier_optional_impl (difficulty);
|
||||
if (!ec && (difficulty > node.config.max_work_generate_difficulty || difficulty < node.network_params.network.publish_thresholds.base))
|
||||
if (!ec && (difficulty > node.config.max_work_generate_difficulty || difficulty < node.network_params.network.publish_thresholds.entry))
|
||||
{
|
||||
ec = nano::error_rpc::difficulty_limit;
|
||||
}
|
||||
|
@ -4956,7 +4970,7 @@ void nano::json_handler::work_generate ()
|
|||
std::stringstream ostream;
|
||||
auto result_difficulty (nano::work_difficulty (work_version, hash, work));
|
||||
response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
|
||||
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, nano::work_threshold (work_version));
|
||||
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_thresholds.base);
|
||||
response_l.put ("multiplier", nano::to_string (result_multiplier));
|
||||
boost::property_tree::write_json (ostream, response_l);
|
||||
rpc_l->response (ostream.str ());
|
||||
|
@ -4970,7 +4984,7 @@ void nano::json_handler::work_generate ()
|
|||
{
|
||||
if (node.local_work_generation_enabled ())
|
||||
{
|
||||
node.work.generate (work_version, hash, callback, difficulty);
|
||||
node.work.generate (work_version, hash, difficulty, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4992,7 +5006,7 @@ void nano::json_handler::work_generate ()
|
|||
auto const & peers_l (secondary_work_peers_l ? node.config.secondary_work_peers : node.config.work_peers);
|
||||
if (node.work_generation_enabled (peers_l))
|
||||
{
|
||||
node.work_generate (work_version, hash, callback, difficulty, account, secondary_work_peers_l);
|
||||
node.work_generate (work_version, hash, difficulty, callback, account, secondary_work_peers_l);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5071,7 +5085,7 @@ void nano::json_handler::work_validate ()
|
|||
auto result_difficulty (nano::work_difficulty (work_version, hash, work));
|
||||
response_l.put ("valid", (result_difficulty >= difficulty) ? "1" : "0");
|
||||
response_l.put ("difficulty", nano::to_string_hex (result_difficulty));
|
||||
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, nano::work_threshold (work_version));
|
||||
auto result_multiplier = nano::difficulty::to_multiplier (result_difficulty, node.network_params.network.publish_thresholds.base);
|
||||
response_l.put ("multiplier", nano::to_string (result_multiplier));
|
||||
}
|
||||
response_errors ();
|
||||
|
|
|
@ -259,7 +259,7 @@ startup_time (std::chrono::steady_clock::now ())
|
|||
if (this->websocket_server->any_subscriber (nano::websocket::topic::active_difficulty))
|
||||
{
|
||||
nano::websocket::message_builder builder;
|
||||
auto msg (builder.difficulty_changed (network_params.network.publish_thresholds.base, active_difficulty));
|
||||
auto msg (builder.difficulty_changed (network_params.network.publish_thresholds.epoch_1, active_difficulty));
|
||||
this->websocket_server->broadcast (msg);
|
||||
}
|
||||
});
|
||||
|
@ -1011,11 +1011,6 @@ bool nano::node::work_generation_enabled (std::vector<std::pair<std::string, uin
|
|||
return !peers_a.empty () || local_work_generation_enabled ();
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a)
|
||||
{
|
||||
return work_generate_blocking (block_a, network_params.network.publish_thresholds.base);
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a, uint64_t difficulty_a)
|
||||
{
|
||||
auto opt_work_l (work_generate_blocking (block_a.work_version (), block_a.root (), difficulty_a, block_a.account ()));
|
||||
|
@ -1026,37 +1021,33 @@ boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & bloc
|
|||
return opt_work_l;
|
||||
}
|
||||
|
||||
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 (version_a, root_a, callback_a, network_params.network.publish_thresholds.base, 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, 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, uint64_t difficulty_a, std::function<void(boost::optional<uint64_t>)> callback_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);
|
||||
if (distributed_work.make (version_a, root_a, peers_l, callback_a, difficulty_a, account_a))
|
||||
if (distributed_work.make (version_a, root_a, peers_l, difficulty_a, callback_a, account_a))
|
||||
{
|
||||
// Error in creating the job (either stopped or work generation is not possible)
|
||||
callback_a (boost::none);
|
||||
}
|
||||
}
|
||||
|
||||
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 (version_a, root_a, network_params.network.publish_thresholds.base, 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;
|
||||
work_generate (
|
||||
version_a, root_a, [&promise](boost::optional<uint64_t> opt_work_a) {
|
||||
version_a, root_a, difficulty_a, [&promise](boost::optional<uint64_t> opt_work_a) {
|
||||
promise.set_value (opt_work_a);
|
||||
},
|
||||
difficulty_a, account_a);
|
||||
account_a);
|
||||
return promise.get_future ().get ();
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::block & block_a)
|
||||
{
|
||||
debug_assert (network_params.network.is_test_network ());
|
||||
return work_generate_blocking (block_a, network_params.network.publish_thresholds.base);
|
||||
}
|
||||
|
||||
boost::optional<uint64_t> nano::node::work_generate_blocking (nano::root const & root_a)
|
||||
{
|
||||
debug_assert (network_params.network.is_test_network ());
|
||||
|
|
|
@ -130,11 +130,8 @@ public:
|
|||
bool work_generation_enabled () 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::block &);
|
||||
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::work_version const, nano::root const &, boost::optional<nano::account> const & = boost::none);
|
||||
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::work_version const, 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 &, uint64_t, std::function<void(boost::optional<uint64_t>)>, boost::optional<nano::account> const & = boost::none, bool const = false);
|
||||
void add_initial_peers ();
|
||||
void block_confirm (std::shared_ptr<nano::block>);
|
||||
bool block_confirmed_or_being_confirmed (nano::transaction const &, nano::block_hash const &);
|
||||
|
@ -195,6 +192,8 @@ public:
|
|||
static double constexpr price_max = 16.0;
|
||||
static double constexpr free_cutoff = 1024.0;
|
||||
// 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 &);
|
||||
|
|
|
@ -162,6 +162,38 @@ nano::account nano::system::account (nano::transaction const & transaction_a, si
|
|||
return nano::account (result);
|
||||
}
|
||||
|
||||
uint64_t nano::system::work_generate_limited (nano::block_hash const & root_a, uint64_t min_a, uint64_t max_a)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
do
|
||||
{
|
||||
result = *work.generate (root_a, min_a);
|
||||
} while (nano::work_difficulty (nano::work_version::work_1, root_a, result) >= max_a);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::state_block> nano::system::upgrade_genesis_epoch (nano::node & node_a, nano::epoch const epoch_a)
|
||||
{
|
||||
bool error{ true };
|
||||
nano::state_block_builder builder;
|
||||
std::error_code ec;
|
||||
auto latest (node_a.latest (nano::test_genesis_key.pub));
|
||||
auto epoch = builder
|
||||
.account (nano::test_genesis_key.pub)
|
||||
.previous (latest)
|
||||
.balance (node_a.balance (nano::test_genesis_key.pub))
|
||||
.link (node_a.ledger.epoch_link (epoch_a))
|
||||
.representative (nano::test_genesis_key.pub)
|
||||
.sign (nano::test_genesis_key.prv, nano::test_genesis_key.pub)
|
||||
.work (*work.generate (latest, nano::work_threshold (nano::work_version::work_1, nano::block_details (epoch_a, false, false, true))))
|
||||
.build (ec);
|
||||
if (!ec && epoch)
|
||||
{
|
||||
error = node_a.process (*epoch).code != nano::process_result::progress;
|
||||
}
|
||||
return !error ? std::move (epoch) : nullptr;
|
||||
}
|
||||
|
||||
void nano::system::deadline_set (std::chrono::duration<double, std::nano> const & delta_a)
|
||||
{
|
||||
deadline = std::chrono::steady_clock::now () + delta_a * deadline_scaling_factor;
|
||||
|
|
|
@ -31,8 +31,11 @@ public:
|
|||
void generate_receive (nano::node &);
|
||||
void generate_send_new (nano::node &, std::vector<nano::account> &);
|
||||
void generate_send_existing (nano::node &, std::vector<nano::account> &);
|
||||
std::unique_ptr<nano::state_block> upgrade_genesis_epoch (nano::node &, nano::epoch const);
|
||||
std::shared_ptr<nano::wallet> wallet (size_t);
|
||||
nano::account account (nano::transaction const &, size_t);
|
||||
/** Generate work with difficulty between \p min_difficulty_a (inclusive) and \p max_difficulty_a (exclusive) */
|
||||
uint64_t work_generate_limited (nano::block_hash const & root_a, uint64_t min_difficulty_a, uint64_t max_difficulty_a);
|
||||
/**
|
||||
* Polls, sleep if there's no work to be done (default 50ms), then check the deadline
|
||||
* @returns 0 or nano::deadline_expired
|
||||
|
|
|
@ -935,6 +935,8 @@ std::shared_ptr<nano::block> nano::wallet::receive_action (nano::block const & s
|
|||
nano::account account;
|
||||
auto hash (send_a.hash ());
|
||||
std::shared_ptr<nano::block> block;
|
||||
nano::block_details details;
|
||||
details.is_receive = true;
|
||||
if (wallets.node.config.receive_minimum.number () <= amount_a.number ())
|
||||
{
|
||||
auto block_transaction (wallets.node.ledger.store.tx_begin_read ());
|
||||
|
@ -957,10 +959,12 @@ std::shared_ptr<nano::block> nano::wallet::receive_action (nano::block const & s
|
|||
if (!new_account)
|
||||
{
|
||||
block = std::make_shared<nano::state_block> (account, info.head, info.representative, info.balance.number () + pending_info.amount.number (), hash, prv, account, work_a);
|
||||
details.epoch = std::max (info.epoch (), send_a.sideband ().details.epoch);
|
||||
}
|
||||
else
|
||||
{
|
||||
block = std::make_shared<nano::state_block> (account, 0, representative_a, pending_info.amount, reinterpret_cast<nano::link const &> (hash), prv, account, work_a);
|
||||
details.epoch = send_a.sideband ().details.epoch;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -985,7 +989,7 @@ std::shared_ptr<nano::block> nano::wallet::receive_action (nano::block const & s
|
|||
}
|
||||
if (block != nullptr)
|
||||
{
|
||||
if (action_complete (block, account, generate_work_a))
|
||||
if (action_complete (block, account, generate_work_a, details))
|
||||
{
|
||||
// Return null block after work generation or ledger process error
|
||||
block = nullptr;
|
||||
|
@ -997,6 +1001,7 @@ std::shared_ptr<nano::block> nano::wallet::receive_action (nano::block const & s
|
|||
std::shared_ptr<nano::block> nano::wallet::change_action (nano::account const & source_a, nano::account const & representative_a, uint64_t work_a, bool generate_work_a)
|
||||
{
|
||||
std::shared_ptr<nano::block> block;
|
||||
nano::block_details details;
|
||||
{
|
||||
auto transaction (wallets.tx_begin_read ());
|
||||
auto block_transaction (wallets.node.store.tx_begin_read ());
|
||||
|
@ -1018,12 +1023,13 @@ std::shared_ptr<nano::block> nano::wallet::change_action (nano::account const &
|
|||
store.work_get (transaction, source_a, work_a);
|
||||
}
|
||||
block = std::make_shared<nano::state_block> (source_a, info.head, representative_a, info.balance, 0, prv, source_a, work_a);
|
||||
details.epoch = info.epoch ();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (block != nullptr)
|
||||
{
|
||||
if (action_complete (block, source_a, generate_work_a))
|
||||
if (action_complete (block, source_a, generate_work_a, details))
|
||||
{
|
||||
// Return null block after work generation or ledger process error
|
||||
block = nullptr;
|
||||
|
@ -1045,6 +1051,8 @@ std::shared_ptr<nano::block> nano::wallet::send_action (nano::account const & so
|
|||
auto error (false);
|
||||
auto cached_block (false);
|
||||
std::shared_ptr<nano::block> block;
|
||||
nano::block_details details;
|
||||
details.is_send = true;
|
||||
if (id_mdb_val)
|
||||
{
|
||||
nano::mdb_val result;
|
||||
|
@ -1087,6 +1095,7 @@ std::shared_ptr<nano::block> nano::wallet::send_action (nano::account const & so
|
|||
store.work_get (transaction, source_a, work_a);
|
||||
}
|
||||
block = std::make_shared<nano::state_block> (source_a, info.head, info.representative, balance - amount_a, account_a, prv, source_a, work_a);
|
||||
details.epoch = info.epoch ();
|
||||
if (id_mdb_val && block != nullptr)
|
||||
{
|
||||
auto status (mdb_put (wallets.env.tx (transaction), wallets.node.wallets.send_action_ids, *id_mdb_val, nano::mdb_val (block->hash ()), 0));
|
||||
|
@ -1100,10 +1109,10 @@ std::shared_ptr<nano::block> nano::wallet::send_action (nano::account const & so
|
|||
}
|
||||
}
|
||||
}
|
||||
return std::make_tuple (block, error, cached_block);
|
||||
return std::make_tuple (block, error, cached_block, details);
|
||||
};
|
||||
|
||||
std::tuple<std::shared_ptr<nano::block>, bool, bool> result;
|
||||
std::tuple<std::shared_ptr<nano::block>, bool, bool, nano::block_details> result;
|
||||
{
|
||||
if (id_mdb_val)
|
||||
{
|
||||
|
@ -1118,11 +1127,12 @@ std::shared_ptr<nano::block> nano::wallet::send_action (nano::account const & so
|
|||
std::shared_ptr<nano::block> block;
|
||||
bool error;
|
||||
bool cached_block;
|
||||
std::tie (block, error, cached_block) = result;
|
||||
nano::block_details details;
|
||||
std::tie (block, error, cached_block, details) = result;
|
||||
|
||||
if (!error && block != nullptr && !cached_block)
|
||||
{
|
||||
if (action_complete (block, source_a, generate_work_a))
|
||||
if (action_complete (block, source_a, generate_work_a, details))
|
||||
{
|
||||
// Return null block after work generation or ledger process error
|
||||
block = nullptr;
|
||||
|
@ -1131,19 +1141,23 @@ std::shared_ptr<nano::block> nano::wallet::send_action (nano::account const & so
|
|||
return block;
|
||||
}
|
||||
|
||||
bool nano::wallet::action_complete (std::shared_ptr<nano::block> const & block_a, nano::account const & account_a, bool const generate_work_a)
|
||||
bool nano::wallet::action_complete (std::shared_ptr<nano::block> const & block_a, nano::account const & account_a, bool const generate_work_a, nano::block_details const & details_a)
|
||||
{
|
||||
bool error{ false };
|
||||
if (block_a != nullptr)
|
||||
{
|
||||
if (nano::work_validate (*block_a))
|
||||
auto required_difficulty{ nano::work_threshold (block_a->work_version (), details_a) };
|
||||
if (block_a->difficulty () < required_difficulty)
|
||||
{
|
||||
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 ();
|
||||
debug_assert (required_difficulty <= wallets.node.config.max_work_generate_difficulty);
|
||||
auto target_difficulty = std::max (required_difficulty, wallets.node.active.limited_active_difficulty ());
|
||||
error = !wallets.node.work_generate_blocking (*block_a, target_difficulty).is_initialized ();
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
error = wallets.node.process_local (block_a, true).code != nano::process_result::progress;
|
||||
debug_assert (error || block_a->sideband ().details == details_a);
|
||||
}
|
||||
if (!error && generate_work_a)
|
||||
{
|
||||
|
@ -1219,7 +1233,7 @@ void nano::wallet::send_async (nano::account const & source_a, nano::account con
|
|||
// 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)
|
||||
{
|
||||
debug_assert (!nano::work_validate (nano::work_version::work_1, root_a, work_a));
|
||||
debug_assert (!nano::work_validate_entry (nano::work_version::work_1, root_a, work_a));
|
||||
debug_assert (store.exists (transaction_a, account_a));
|
||||
auto block_transaction (wallets.node.store.tx_begin_read ());
|
||||
auto latest (wallets.node.ledger.latest_root (block_transaction, account_a));
|
||||
|
@ -1369,7 +1383,7 @@ void nano::wallet::work_cache_blocking (nano::account const & account_a, nano::r
|
|||
{
|
||||
if (wallets.node.work_generation_enabled ())
|
||||
{
|
||||
auto opt_work_l (wallets.node.work_generate_blocking (nano::work_version::work_1, root_a, account_a));
|
||||
auto opt_work_l (wallets.node.work_generate_blocking (nano::work_version::work_1, root_a, wallets.node.network_params.network.publish_thresholds.base, account_a));
|
||||
if (opt_work_l.is_initialized ())
|
||||
{
|
||||
auto transaction_l (wallets.tx_begin_write ());
|
||||
|
@ -1444,7 +1458,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
|
|||
if (active_difficulty > block_a->difficulty () && watcher_l->node.work_generation_enabled ())
|
||||
{
|
||||
watcher_l->node.work_generate (
|
||||
block_a->work_version (), block_a->root (), [watcher_l, block_a, root_a](boost::optional<uint64_t> work_a) {
|
||||
block_a->work_version (), block_a->root (), active_difficulty, [watcher_l, block_a, root_a](boost::optional<uint64_t> work_a) {
|
||||
if (block_a != nullptr && watcher_l != nullptr && !watcher_l->stopped)
|
||||
{
|
||||
bool updated_l{ false };
|
||||
|
@ -1469,7 +1483,7 @@ void nano::work_watcher::watching (nano::qualified_root const & root_a, std::sha
|
|||
}
|
||||
}
|
||||
},
|
||||
active_difficulty, block_a->account ());
|
||||
block_a->account ());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
std::shared_ptr<nano::block> change_action (nano::account const &, nano::account const &, uint64_t = 0, bool = true);
|
||||
std::shared_ptr<nano::block> receive_action (nano::block const &, nano::account const &, nano::uint128_union const &, uint64_t = 0, bool = true);
|
||||
std::shared_ptr<nano::block> send_action (nano::account const &, nano::account const &, nano::uint128_t const &, uint64_t = 0, bool = true, boost::optional<std::string> = {});
|
||||
bool action_complete (std::shared_ptr<nano::block> const &, nano::account const &, bool const);
|
||||
bool action_complete (std::shared_ptr<nano::block> const &, nano::account const &, bool const, nano::block_details const &);
|
||||
wallet (bool &, nano::transaction &, nano::wallets &, std::string const &);
|
||||
wallet (bool &, nano::transaction &, nano::wallets &, std::string const &, std::string const &);
|
||||
void enter_initial_password ();
|
||||
|
|
|
@ -797,7 +797,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano
|
|||
request_l.put ("version", nano::to_string (version_a));
|
||||
request_l.put ("hash", root_a.to_string ());
|
||||
request_l.put ("difficulty", nano::to_string_hex (difficulty_a));
|
||||
auto request_multiplier_l (nano::difficulty::to_multiplier (difficulty_a, nano::work_threshold (version_a)));
|
||||
auto request_multiplier_l (nano::difficulty::to_multiplier (difficulty_a, publish_threshold_a));
|
||||
request_l.put ("multiplier", nano::to_string (request_multiplier_l));
|
||||
work_l.add_child ("request", request_l);
|
||||
|
||||
|
@ -808,7 +808,7 @@ nano::websocket::message nano::websocket::message_builder::work_generation (nano
|
|||
result_l.put ("work", nano::to_string_hex (work_a));
|
||||
auto result_difficulty_l (nano::work_difficulty (version_a, root_a, work_a));
|
||||
result_l.put ("difficulty", nano::to_string_hex (result_difficulty_l));
|
||||
auto result_multiplier_l (nano::difficulty::to_multiplier (result_difficulty_l, nano::work_threshold (version_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));
|
||||
work_l.add_child ("result", result_l);
|
||||
}
|
||||
|
|
|
@ -2002,7 +2002,7 @@ wallet (wallet_a)
|
|||
{
|
||||
show_label_ok (*status);
|
||||
this->status->setText ("");
|
||||
if (!nano::work_validate (*block_l))
|
||||
if (!nano::work_validate_entry (*block_l))
|
||||
{
|
||||
this->wallet.node.process_active (std::move (block_l));
|
||||
}
|
||||
|
|
|
@ -727,7 +727,7 @@ TEST (wallet, seed_work_generation)
|
|||
ASSERT_NO_ERROR (ec);
|
||||
}
|
||||
auto transaction (system.nodes[0]->store.tx_begin_read ());
|
||||
ASSERT_FALSE (nano::work_validate (nano::work_version::work_1, system.nodes[0]->ledger.latest_root (transaction, pub), work));
|
||||
ASSERT_GE (nano::work_difficulty (nano::work_version::work_1, system.nodes[0]->ledger.latest_root (transaction, pub), work), nano::work_threshold_base (nano::work_version::work_1));
|
||||
}
|
||||
|
||||
TEST (wallet, backup_seed)
|
||||
|
|
|
@ -619,6 +619,55 @@ TEST (rpc, send_idempotent)
|
|||
ASSERT_EQ (std::error_code (nano::error_common::insufficient_balance).message (), response3.json.get<std::string> ("error"));
|
||||
}
|
||||
|
||||
TEST (rpc, send_epoch_2)
|
||||
{
|
||||
nano::system system;
|
||||
auto & node = *add_ipc_enabled_node (system);
|
||||
|
||||
// Upgrade the genesis account to epoch 2
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_1));
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_2));
|
||||
|
||||
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
|
||||
auto target_difficulty = nano::work_threshold (nano::work_version::work_1, nano::block_details (nano::epoch::epoch_2, true, false, false));
|
||||
ASSERT_LT (node.network_params.network.publish_thresholds.entry, target_difficulty);
|
||||
auto min_difficulty = node.network_params.network.publish_thresholds.entry;
|
||||
|
||||
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 ();
|
||||
boost::property_tree::ptree request;
|
||||
std::string wallet;
|
||||
node.wallets.items.begin ()->first.encode_hex (wallet);
|
||||
request.put ("wallet", wallet);
|
||||
request.put ("action", "send");
|
||||
request.put ("source", nano::test_genesis_key.pub.to_account ());
|
||||
request.put ("destination", nano::keypair ().pub.to_account ());
|
||||
request.put ("amount", "1");
|
||||
|
||||
// Test that the correct error is given if there is insufficient work
|
||||
auto insufficient = system.work_generate_limited (nano::genesis_hash, min_difficulty, target_difficulty);
|
||||
request.put ("work", nano::to_string_hex (insufficient));
|
||||
{
|
||||
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);
|
||||
std::error_code ec (nano::error_common::invalid_work);
|
||||
ASSERT_EQ (1, response.json.count ("error"));
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, stop)
|
||||
{
|
||||
nano::system system;
|
||||
|
@ -1789,7 +1838,7 @@ TEST (rpc, process_block_with_work_watcher)
|
|||
auto latest (node1.latest (nano::test_genesis_key.pub));
|
||||
auto send (std::make_shared<nano::state_block> (nano::test_genesis_key.pub, latest, nano::test_genesis_key.pub, nano::genesis_amount - 100, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *system.work.generate (latest)));
|
||||
auto difficulty1 (send->difficulty ());
|
||||
auto multiplier1 = nano::difficulty::to_multiplier (difficulty1, nano::work_threshold (send->work_version ()));
|
||||
auto multiplier1 = nano::difficulty::to_multiplier (difficulty1, node1.active.active_difficulty ());
|
||||
nano::node_rpc_config node_rpc_config;
|
||||
nano::ipc::ipc_server ipc_server (node1, node_rpc_config);
|
||||
nano::rpc_config rpc_config (nano::get_available_port (), true);
|
||||
|
@ -2003,14 +2052,12 @@ TEST (rpc, process_subtype_open)
|
|||
{
|
||||
nano::system system;
|
||||
auto & node1 = *add_ipc_enabled_node (system);
|
||||
system.add_node ();
|
||||
auto & node2 = *system.add_node ();
|
||||
nano::keypair key;
|
||||
auto latest (node1.latest (nano::test_genesis_key.pub));
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node1.work_generate_blocking (latest));
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, send).code);
|
||||
}
|
||||
ASSERT_EQ (nano::process_result::progress, node1.process (send).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node2.process (send).code);
|
||||
scoped_io_thread_name_change scoped_thread_name_io;
|
||||
node1.active.insert (std::make_shared<nano::state_block> (send));
|
||||
nano::state_block open (key.pub, 0, key.pub, nano::Gxrb_ratio, send.hash (), key.prv, key.pub, *node1.work_generate_blocking (key.pub));
|
||||
|
@ -2053,7 +2100,8 @@ TEST (rpc, process_subtype_open)
|
|||
ASSERT_EQ (200, response3.status);
|
||||
ASSERT_EQ (open.hash ().to_string (), response3.json.get<std::string> ("hash"));
|
||||
system.deadline_set (10s);
|
||||
while (system.nodes[1]->latest (key.pub) != open.hash ())
|
||||
auto now (std::chrono::steady_clock::now ());
|
||||
while (node2.latest (key.pub) != open.hash ())
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
|
@ -2063,13 +2111,11 @@ TEST (rpc, process_subtype_receive)
|
|||
{
|
||||
nano::system system;
|
||||
auto & node1 = *add_ipc_enabled_node (system);
|
||||
system.add_node ();
|
||||
auto & node2 = *system.add_node ();
|
||||
auto latest (node1.latest (nano::test_genesis_key.pub));
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node1.work_generate_blocking (latest));
|
||||
{
|
||||
auto transaction (node1.store.tx_begin_write ());
|
||||
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, send).code);
|
||||
}
|
||||
ASSERT_EQ (nano::process_result::progress, node1.process (send).code);
|
||||
ASSERT_EQ (nano::process_result::progress, node2.process (send).code);
|
||||
scoped_io_thread_name_change scoped_thread_name_io;
|
||||
node1.active.insert (std::make_shared<nano::state_block> (send));
|
||||
nano::state_block receive (nano::test_genesis_key.pub, send.hash (), nano::test_genesis_key.pub, nano::genesis_amount, send.hash (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, *node1.work_generate_blocking (send.hash ()));
|
||||
|
@ -2113,12 +2159,49 @@ TEST (rpc, process_subtype_receive)
|
|||
ASSERT_EQ (200, response3.status);
|
||||
ASSERT_EQ (receive.hash ().to_string (), response3.json.get<std::string> ("hash"));
|
||||
system.deadline_set (10s);
|
||||
while (system.nodes[1]->latest (nano::test_genesis_key.pub) != receive.hash ())
|
||||
while (node2.latest (nano::test_genesis_key.pub) != receive.hash ())
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, process_ledger_insufficient_work)
|
||||
{
|
||||
nano::system system;
|
||||
auto & node = *add_ipc_enabled_node (system);
|
||||
ASSERT_LT (node.network_params.network.publish_thresholds.entry, node.network_params.network.publish_thresholds.epoch_1);
|
||||
auto latest (node.latest (nano::test_genesis_key.pub));
|
||||
auto min_difficulty = node.network_params.network.publish_thresholds.entry;
|
||||
auto max_difficulty = node.network_params.network.publish_thresholds.epoch_1;
|
||||
nano::state_block send (nano::genesis_account, latest, nano::genesis_account, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.pub, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work_generate_limited (latest, min_difficulty, max_difficulty));
|
||||
ASSERT_LT (send.difficulty (), max_difficulty);
|
||||
ASSERT_GE (send.difficulty (), min_difficulty);
|
||||
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 ();
|
||||
boost::property_tree::ptree request;
|
||||
request.put ("action", "process");
|
||||
std::string json;
|
||||
send.serialize_json (json);
|
||||
request.put ("block", json);
|
||||
request.put ("subtype", "send");
|
||||
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);
|
||||
std::error_code ec (nano::error_process::insufficient_work);
|
||||
ASSERT_EQ (1, response.json.count ("error"));
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
}
|
||||
|
||||
TEST (rpc, keepalive)
|
||||
{
|
||||
nano::system system;
|
||||
|
@ -2221,13 +2304,13 @@ TEST (rpc, payment_begin_end)
|
|||
root1 = node1->ledger.latest_root (transaction, account);
|
||||
}
|
||||
uint64_t work (0);
|
||||
while (!nano::work_validate (nano::work_version::work_1, root1, work))
|
||||
while (nano::work_difficulty (nano::work_version::work_1, root1, work) >= nano::work_threshold_base (nano::work_version::work_1))
|
||||
{
|
||||
++work;
|
||||
ASSERT_LT (work, 50);
|
||||
}
|
||||
system.deadline_set (10s);
|
||||
while (nano::work_validate (nano::work_version::work_1, root1, work))
|
||||
while (nano::work_difficulty (nano::work_version::work_1, root1, work) < nano::work_threshold_base (nano::work_version::work_1))
|
||||
{
|
||||
auto ec = system.poll ();
|
||||
auto transaction (wallet->wallets.tx_begin_read ());
|
||||
|
@ -2882,7 +2965,7 @@ TEST (rpc, work_generate_difficulty)
|
|||
ASSERT_EQ (result_difficulty, response_difficulty);
|
||||
auto multiplier = response.json.get<double> ("multiplier");
|
||||
// Expected multiplier from base threshold, not from the given difficulty
|
||||
ASSERT_EQ (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_thresholds.base), multiplier);
|
||||
ASSERT_NEAR (nano::difficulty::to_multiplier (result_difficulty, node->network_params.network.publish_thresholds.base), multiplier, 1e-10);
|
||||
ASSERT_GE (result_difficulty, difficulty);
|
||||
}
|
||||
{
|
||||
|
@ -2920,7 +3003,7 @@ TEST (rpc, work_generate_multiplier)
|
|||
{
|
||||
nano::system system;
|
||||
nano::node_config node_config (nano::get_available_port (), system.logging);
|
||||
node_config.max_work_generate_difficulty = 0xffff000000000000;
|
||||
node_config.max_work_generate_difficulty = 0xfffff00000000000;
|
||||
auto node = add_ipc_enabled_node (system, node_config);
|
||||
scoped_io_thread_name_change scoped_thread_name_io;
|
||||
nano::node_rpc_config node_rpc_config;
|
||||
|
@ -2947,9 +3030,14 @@ TEST (rpc, work_generate_multiplier)
|
|||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
ASSERT_EQ (200, response.status);
|
||||
auto work_text (response.json.get<std::string> ("work"));
|
||||
auto work_text (response.json.get_optional<std::string> ("work"));
|
||||
if (!work_text)
|
||||
{
|
||||
std::cout << response.json.get<std::string> ("error") << std::endl;
|
||||
}
|
||||
ASSERT_TRUE (work_text.is_initialized ());
|
||||
uint64_t work;
|
||||
ASSERT_FALSE (nano::from_string_hex (work_text, work));
|
||||
ASSERT_FALSE (nano::from_string_hex (*work_text, work));
|
||||
auto result_difficulty (nano::work_difficulty (nano::work_version::work_1, hash, work));
|
||||
auto response_difficulty_text (response.json.get<std::string> ("difficulty"));
|
||||
uint64_t response_difficulty;
|
||||
|
@ -3008,7 +3096,7 @@ TEST (rpc, work_cancel)
|
|||
system.deadline_set (10s);
|
||||
while (!done)
|
||||
{
|
||||
system.work.generate (hash1, [&done](boost::optional<uint64_t> work_a) {
|
||||
system.work.generate (nano::work_version::work_1, hash1, node1.network_params.network.publish_thresholds.base, [&done](boost::optional<uint64_t> work_a) {
|
||||
done = !work_a;
|
||||
});
|
||||
test_response response1 (request1, rpc.config.port, system.io_ctx);
|
||||
|
@ -3041,12 +3129,12 @@ TEST (rpc, work_peer_bad)
|
|||
node2.config.work_peers.push_back (std::make_pair (boost::asio::ip::address_v6::any ().to_string (), 0));
|
||||
nano::block_hash hash1 (1);
|
||||
std::atomic<uint64_t> work (0);
|
||||
node2.work_generate (nano::work_version::work_1, hash1, [&work](boost::optional<uint64_t> work_a) {
|
||||
node2.work_generate (nano::work_version::work_1, hash1, node2.network_params.network.publish_thresholds.base, [&work](boost::optional<uint64_t> work_a) {
|
||||
ASSERT_TRUE (work_a.is_initialized ());
|
||||
work = *work_a;
|
||||
});
|
||||
system.deadline_set (5s);
|
||||
while (nano::work_validate (nano::work_version::work_1, hash1, work))
|
||||
while (nano::work_difficulty (nano::work_version::work_1, hash1, work) < nano::work_threshold_base (nano::work_version::work_1))
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
|
@ -3070,13 +3158,13 @@ TEST (rpc, work_peer_one)
|
|||
rpc.start ();
|
||||
node2.config.work_peers.push_back (std::make_pair (node1.network.endpoint ().address ().to_string (), rpc.config.port));
|
||||
nano::keypair key1;
|
||||
uint64_t work (0);
|
||||
node2.work_generate (nano::work_version::work_1, key1.pub, [&work](boost::optional<uint64_t> work_a) {
|
||||
std::atomic<uint64_t> work (0);
|
||||
node2.work_generate (nano::work_version::work_1, key1.pub, node1.network_params.network.publish_thresholds.base, [&work](boost::optional<uint64_t> work_a) {
|
||||
ASSERT_TRUE (work_a.is_initialized ());
|
||||
work = *work_a;
|
||||
});
|
||||
system.deadline_set (5s);
|
||||
while (nano::work_validate (nano::work_version::work_1, key1.pub, work))
|
||||
while (nano::work_difficulty (nano::work_version::work_1, key1.pub, work) < nano::work_threshold_base (nano::work_version::work_1))
|
||||
{
|
||||
ASSERT_NO_ERROR (system.poll ());
|
||||
}
|
||||
|
@ -3118,10 +3206,10 @@ TEST (rpc, work_peer_many)
|
|||
for (auto i (0); i < works.size (); ++i)
|
||||
{
|
||||
nano::keypair key1;
|
||||
node1.work_generate (nano::work_version::work_1, key1.pub, [& work = works[i]](boost::optional<uint64_t> work_a) {
|
||||
node1.work_generate (nano::work_version::work_1, key1.pub, node1.network_params.network.publish_thresholds.base, [& work = works[i]](boost::optional<uint64_t> work_a) {
|
||||
work = *work_a;
|
||||
});
|
||||
while (nano::work_validate (nano::work_version::work_1, key1.pub, works[i]))
|
||||
while (nano::work_difficulty (nano::work_version::work_1, key1.pub, works[i]) < nano::work_threshold_base (nano::work_version::work_1))
|
||||
{
|
||||
system1.poll ();
|
||||
system2.poll ();
|
||||
|
@ -3571,6 +3659,54 @@ TEST (rpc, account_representative_set_work_disabled)
|
|||
}
|
||||
}
|
||||
|
||||
TEST (rpc, account_representative_set_epoch_2)
|
||||
{
|
||||
nano::system system;
|
||||
auto & node = *add_ipc_enabled_node (system);
|
||||
|
||||
// Upgrade the genesis account to epoch 2
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_1));
|
||||
ASSERT_NE (nullptr, system.upgrade_genesis_epoch (node, nano::epoch::epoch_2));
|
||||
|
||||
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv, false);
|
||||
|
||||
auto target_difficulty = nano::work_threshold (nano::work_version::work_1, nano::block_details (nano::epoch::epoch_2, false, false, false));
|
||||
ASSERT_LT (node.network_params.network.publish_thresholds.entry, target_difficulty);
|
||||
auto min_difficulty = node.network_params.network.publish_thresholds.entry;
|
||||
|
||||
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 ();
|
||||
boost::property_tree::ptree request;
|
||||
std::string wallet;
|
||||
node.wallets.items.begin ()->first.encode_hex (wallet);
|
||||
request.put ("wallet", wallet);
|
||||
request.put ("action", "account_representative_set");
|
||||
request.put ("account", nano::test_genesis_key.pub.to_account ());
|
||||
request.put ("representative", nano::keypair ().pub.to_account ());
|
||||
|
||||
// Test that the correct error is given if there is insufficient work
|
||||
auto insufficient = system.work_generate_limited (nano::genesis_hash, min_difficulty, target_difficulty);
|
||||
request.put ("work", nano::to_string_hex (insufficient));
|
||||
{
|
||||
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);
|
||||
std::error_code ec (nano::error_common::invalid_work);
|
||||
ASSERT_EQ (1, response.json.count ("error"));
|
||||
ASSERT_EQ (response.json.get<std::string> ("error"), ec.message ());
|
||||
}
|
||||
}
|
||||
|
||||
TEST (rpc, bootstrap)
|
||||
{
|
||||
nano::system system0;
|
||||
|
@ -5775,7 +5911,7 @@ TEST (rpc, block_create_state_request_work)
|
|||
boost::property_tree::read_json (block_stream, block_l);
|
||||
auto block (nano::deserialize_block_json (block_l));
|
||||
ASSERT_NE (nullptr, block);
|
||||
ASSERT_FALSE (nano::work_validate (*block));
|
||||
ASSERT_GE (block->difficulty (), nano::work_threshold_base (nano::work_version::work_1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7248,13 +7384,13 @@ TEST (rpc, active_difficulty)
|
|||
auto network_minimum_text (response.json.get<std::string> ("network_minimum"));
|
||||
uint64_t network_minimum;
|
||||
ASSERT_FALSE (nano::from_string_hex (network_minimum_text, network_minimum));
|
||||
ASSERT_EQ (node->network_params.network.publish_thresholds.base, network_minimum);
|
||||
ASSERT_EQ (node->network_params.network.publish_thresholds.epoch_1, network_minimum);
|
||||
auto multiplier (response.json.get<double> ("multiplier"));
|
||||
ASSERT_NEAR (expected_multiplier, multiplier, 1e-6);
|
||||
auto network_current_text (response.json.get<std::string> ("network_current"));
|
||||
uint64_t network_current;
|
||||
ASSERT_FALSE (nano::from_string_hex (network_current_text, network_current));
|
||||
ASSERT_EQ (nano::difficulty::from_multiplier (expected_multiplier, node->network_params.network.publish_thresholds.base), network_current);
|
||||
ASSERT_EQ (nano::difficulty::from_multiplier (expected_multiplier, node->network_params.network.publish_thresholds.epoch_1), network_current);
|
||||
ASSERT_EQ (response.json.not_found (), response.json.find ("difficulty_trend"));
|
||||
}
|
||||
// Test include_trend optional
|
||||
|
|
|
@ -783,7 +783,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 & block_a, nano::signature_verification verification)
|
||||
{
|
||||
debug_assert (network_params.network.is_test_network () || !nano::work_validate (block_a));
|
||||
debug_assert (!nano::work_validate_entry (block_a) || network_params.network.is_test_network ());
|
||||
ledger_processor processor (*this, transaction_a, verification);
|
||||
block_a.visit (processor);
|
||||
if (processor.result.code == nano::process_result::progress)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue