Epoch 1 legacy blocks work validation before processing (#2850)
* Epoch 1 legacy blocks work validation before processing Legacy blocks are always epoch 0, cannot use lower epoch_2_receive difficulty * Move vote block work validation to TCP realtime server * Required header * Better logging for bulk pull/push invalid work * Update new test with dev network
This commit is contained in:
parent
d656e87845
commit
84c7248aa1
9 changed files with 120 additions and 26 deletions
|
|
@ -147,7 +147,11 @@ TEST (difficulty, network_constants)
|
|||
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.entry, nano::work_threshold_entry (version, nano::block_type::state));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold_entry (version, nano::block_type::send));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold_entry (version, nano::block_type::receive));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold_entry (version, nano::block_type::open));
|
||||
ASSERT_EQ (constants.publish_thresholds.epoch_1, nano::work_threshold_entry (version, nano::block_type::change));
|
||||
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)));
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ TEST (network, send_valid_publish)
|
|||
}
|
||||
}
|
||||
|
||||
TEST (network, send_insufficient_work)
|
||||
TEST (network, send_insufficient_work_udp)
|
||||
{
|
||||
nano::system system;
|
||||
nano::node_flags node_flags;
|
||||
|
|
@ -305,6 +305,41 @@ TEST (network, send_insufficient_work)
|
|||
ASSERT_EQ (1, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work));
|
||||
}
|
||||
|
||||
TEST (network, send_insufficient_work)
|
||||
{
|
||||
nano::system system (2);
|
||||
auto & node1 = *system.nodes[0];
|
||||
auto & node2 = *system.nodes[1];
|
||||
// Block zero work
|
||||
auto block1 (std::make_shared<nano::send_block> (0, 1, 20, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, 0));
|
||||
nano::publish publish1 (block1);
|
||||
auto tcp_channel (node1.network.tcp_channels.find_channel (nano::transport::map_endpoint_to_tcp (node2.network.endpoint ())));
|
||||
tcp_channel->send (publish1, [](boost::system::error_code const & ec, size_t size) {});
|
||||
ASSERT_EQ (0, node1.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work));
|
||||
ASSERT_TIMELY (10s, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work) != 0);
|
||||
ASSERT_EQ (1, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work));
|
||||
// Legacy block work between epoch_2_recieve & epoch_1
|
||||
auto block2 (std::make_shared<nano::send_block> (block1->hash (), 1, 20, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, system.work_generate_limited (block1->hash (), node1.network_params.network.publish_thresholds.epoch_2_receive, node1.network_params.network.publish_thresholds.epoch_1 - 1)));
|
||||
nano::publish publish2 (block2);
|
||||
tcp_channel->send (publish2, [](boost::system::error_code const & ec, size_t size) {});
|
||||
ASSERT_TIMELY (10s, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work) != 1);
|
||||
ASSERT_EQ (2, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work));
|
||||
// Legacy block work epoch_1
|
||||
auto block3 (std::make_shared<nano::send_block> (block2->hash (), 1, 20, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, *system.work.generate (block2->hash (), node1.network_params.network.publish_thresholds.epoch_2)));
|
||||
nano::publish publish3 (block3);
|
||||
tcp_channel->send (publish3, [](boost::system::error_code const & ec, size_t size) {});
|
||||
ASSERT_EQ (0, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in));
|
||||
ASSERT_TIMELY (10s, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in) != 0);
|
||||
ASSERT_EQ (1, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in));
|
||||
// State block work epoch_2_recieve
|
||||
auto block4 (std::make_shared<nano::state_block> (nano::dev_genesis_key.pub, block1->hash (), nano::dev_genesis_key.pub, 20, 1, nano::dev_genesis_key.prv, nano::dev_genesis_key.pub, system.work_generate_limited (block1->hash (), node1.network_params.network.publish_thresholds.epoch_2_receive, node1.network_params.network.publish_thresholds.epoch_1 - 1)));
|
||||
nano::publish publish4 (block4);
|
||||
tcp_channel->send (publish4, [](boost::system::error_code const & ec, size_t size) {});
|
||||
ASSERT_TIMELY (10s, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in) != 0);
|
||||
ASSERT_EQ (1, node2.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::in));
|
||||
ASSERT_EQ (2, node2.stats.count (nano::stat::type::error, nano::stat::detail::insufficient_work));
|
||||
}
|
||||
|
||||
TEST (receivable_processor, confirm_insufficient_pos)
|
||||
{
|
||||
nano::system system (1);
|
||||
|
|
|
|||
|
|
@ -24,12 +24,12 @@ std::string nano::to_string (nano::work_version const version_a)
|
|||
|
||||
bool nano::work_validate_entry (nano::block const & block_a)
|
||||
{
|
||||
return block_a.difficulty () < nano::work_threshold_entry (block_a.work_version ());
|
||||
return block_a.difficulty () < nano::work_threshold_entry (block_a.work_version (), block_a.type ());
|
||||
}
|
||||
|
||||
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_entry (version_a);
|
||||
return nano::work_difficulty (version_a, root_a, work_a) < nano::work_threshold_entry (version_a, nano::block_type::state);
|
||||
}
|
||||
|
||||
uint64_t nano::work_difficulty (nano::work_version const version_a, nano::root const & root_a, uint64_t const work_a)
|
||||
|
|
@ -60,16 +60,24 @@ uint64_t nano::work_threshold_base (nano::work_version const version_a)
|
|||
return result;
|
||||
}
|
||||
|
||||
uint64_t nano::work_threshold_entry (nano::work_version const version_a)
|
||||
uint64_t nano::work_threshold_entry (nano::work_version const version_a, nano::block_type const type_a)
|
||||
{
|
||||
uint64_t result{ std::numeric_limits<uint64_t>::max () };
|
||||
switch (version_a)
|
||||
if (type_a == nano::block_type::state)
|
||||
{
|
||||
case nano::work_version::work_1:
|
||||
result = nano::work_v1::threshold_entry ();
|
||||
break;
|
||||
default:
|
||||
debug_assert (false && "Invalid version specified to work_threshold_entry");
|
||||
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");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static nano::network_constants network_constants;
|
||||
result = network_constants.publish_thresholds.epoch_1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ std::string to_string (nano::work_version const version_a);
|
|||
|
||||
class block;
|
||||
class block_details;
|
||||
enum class block_type : uint8_t;
|
||||
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);
|
||||
|
||||
uint64_t work_threshold_base (nano::work_version const);
|
||||
uint64_t work_threshold_entry (nano::work_version const);
|
||||
uint64_t work_threshold_entry (nano::work_version const, nano::block_type const);
|
||||
// Ledger threshold
|
||||
uint64_t work_threshold (nano::work_version const, nano::block_details const);
|
||||
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
|
|||
connection->connections->pool_connection (connection);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (block == nullptr)
|
||||
{
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
{
|
||||
|
|
@ -268,6 +268,14 @@ void nano::bulk_pull_client::received_block (boost::system::error_code const & e
|
|||
}
|
||||
connection->node->stats.inc (nano::stat::type::bootstrap, nano::stat::detail::bulk_pull_deserialize_receive_block, nano::stat::dir::in);
|
||||
}
|
||||
else // Work invalid
|
||||
{
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
{
|
||||
connection->node->logger.try_log (boost::str (boost::format ("Insufficient work for bulk pull block: %1%") % block->hash ().to_string ()));
|
||||
}
|
||||
connection->node->stats.inc_detail_only (nano::stat::type::error, nano::stat::detail::insufficient_work);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -237,12 +237,20 @@ void nano::bulk_push_server::received_block (boost::system::error_code const & e
|
|||
connection->node->process_active (std::move (block));
|
||||
throttled_receive ();
|
||||
}
|
||||
else
|
||||
else if (block == nullptr)
|
||||
{
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
{
|
||||
connection->node->logger.try_log ("Error deserializing block received from pull request");
|
||||
}
|
||||
}
|
||||
else // Work invalid
|
||||
{
|
||||
if (connection->node->config.logging.bulk_pull_logging ())
|
||||
{
|
||||
connection->node->logger.try_log (boost::str (boost::format ("Insufficient work for bulk push block: %1%") % block->hash ().to_string ()));
|
||||
}
|
||||
connection->node->stats.inc_detail_only (nano::stat::type::error, nano::stat::detail::insufficient_work);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <nano/node/transport/tcp.hpp>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/variant/get.hpp>
|
||||
|
||||
nano::bootstrap_listener::bootstrap_listener (uint16_t port_a, nano::node & node_a) :
|
||||
node (node_a),
|
||||
|
|
@ -431,7 +432,14 @@ void nano::bootstrap_server::receive_publish_action (boost::system::error_code c
|
|||
{
|
||||
if (is_realtime_connection ())
|
||||
{
|
||||
add_request (std::unique_ptr<nano::message> (request.release ()));
|
||||
if (!nano::work_validate_entry (*request->block))
|
||||
{
|
||||
add_request (std::unique_ptr<nano::message> (request.release ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
node->stats.inc_detail_only (nano::stat::type::error, nano::stat::detail::insufficient_work);
|
||||
}
|
||||
}
|
||||
receive ();
|
||||
}
|
||||
|
|
@ -484,7 +492,26 @@ void nano::bootstrap_server::receive_confirm_ack_action (boost::system::error_co
|
|||
{
|
||||
if (is_realtime_connection ())
|
||||
{
|
||||
add_request (std::unique_ptr<nano::message> (request.release ()));
|
||||
bool process_vote (true);
|
||||
if (header_a.block_type () != nano::block_type::not_a_block)
|
||||
{
|
||||
for (auto & vote_block : request->vote->blocks)
|
||||
{
|
||||
if (!vote_block.which ())
|
||||
{
|
||||
auto block (boost::get<std::shared_ptr<nano::block>> (vote_block));
|
||||
if (nano::work_validate_entry (*block))
|
||||
{
|
||||
process_vote = false;
|
||||
node->stats.inc_detail_only (nano::stat::type::error, nano::stat::detail::insufficient_work);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (process_vote)
|
||||
{
|
||||
add_request (std::unique_ptr<nano::message> (request.release ()));
|
||||
}
|
||||
}
|
||||
receive ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4741,7 +4741,7 @@ void nano::json_handler::work_generate ()
|
|||
auto hash (hash_impl ());
|
||||
auto difficulty (difficulty_optional_impl (work_version));
|
||||
multiplier_optional_impl (work_version, difficulty);
|
||||
if (!ec && (difficulty > node.max_work_generate_difficulty (work_version) || difficulty < nano::work_threshold_entry (work_version)))
|
||||
if (!ec && (difficulty > node.max_work_generate_difficulty (work_version) || difficulty < nano::work_threshold_entry (work_version, nano::block_type::state)))
|
||||
{
|
||||
ec = nano::error_rpc::difficulty_limit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -447,18 +447,21 @@ public:
|
|||
node.stats.inc (nano::stat::type::message, nano::stat::detail::confirm_ack, nano::stat::dir::in);
|
||||
if (!message_a.vote->account.is_zero ())
|
||||
{
|
||||
for (auto & vote_block : message_a.vote->blocks)
|
||||
if (message_a.header.block_type () != nano::block_type::not_a_block)
|
||||
{
|
||||
if (!vote_block.which ())
|
||||
for (auto & vote_block : message_a.vote->blocks)
|
||||
{
|
||||
auto block (boost::get<std::shared_ptr<nano::block>> (vote_block));
|
||||
if (!node.block_processor.full ())
|
||||
if (!vote_block.which ())
|
||||
{
|
||||
node.process_active (block);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.stats.inc (nano::stat::type::drop, nano::stat::detail::confirm_ack, nano::stat::dir::in);
|
||||
auto block (boost::get<std::shared_ptr<nano::block>> (vote_block));
|
||||
if (!node.block_processor.full ())
|
||||
{
|
||||
node.process_active (block);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.stats.inc (nano::stat::type::drop, nano::stat::detail::confirm_ack, nano::stat::dir::in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue