Remove unused signature checking classes
This commit is contained in:
parent
dd121a84db
commit
dc536b93a6
15 changed files with 6 additions and 811 deletions
|
|
@ -41,7 +41,6 @@ add_executable(
|
|||
scheduler_buckets.cpp
|
||||
request_aggregator.cpp
|
||||
signal_manager.cpp
|
||||
signing.cpp
|
||||
socket.cpp
|
||||
system.cpp
|
||||
telemetry.cpp
|
||||
|
|
|
|||
|
|
@ -1,250 +0,0 @@
|
|||
#include <nano/node/signatures.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST (signature_checker, empty)
|
||||
{
|
||||
nano::signature_checker checker (0);
|
||||
nano::signature_check_set check = { 0, nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||
checker.verify (check);
|
||||
}
|
||||
|
||||
TEST (signature_checker, bulk_single_thread)
|
||||
{
|
||||
nano::keypair key;
|
||||
nano::block_builder builder;
|
||||
auto block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
nano::signature_checker checker (0);
|
||||
std::vector<nano::uint256_union> hashes;
|
||||
size_t size (1000);
|
||||
hashes.reserve (size);
|
||||
std::vector<unsigned char const *> messages;
|
||||
messages.reserve (size);
|
||||
std::vector<size_t> lengths;
|
||||
lengths.reserve (size);
|
||||
std::vector<unsigned char const *> pub_keys;
|
||||
pub_keys.reserve (size);
|
||||
std::vector<unsigned char const *> signatures;
|
||||
signatures.reserve (size);
|
||||
std::vector<int> verifications;
|
||||
verifications.resize (size);
|
||||
for (auto i (0); i < size; ++i)
|
||||
{
|
||||
hashes.push_back (block->hash ());
|
||||
messages.push_back (hashes.back ().bytes.data ());
|
||||
lengths.push_back (sizeof (decltype (hashes)::value_type));
|
||||
pub_keys.push_back (block->hashables.account.bytes.data ());
|
||||
signatures.push_back (block->signature.bytes.data ());
|
||||
}
|
||||
nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data () };
|
||||
checker.verify (check);
|
||||
bool all_valid = std::all_of (verifications.cbegin (), verifications.cend (), [] (auto verification) { return verification == 1; });
|
||||
ASSERT_TRUE (all_valid);
|
||||
}
|
||||
|
||||
TEST (signature_checker, many_multi_threaded)
|
||||
{
|
||||
nano::signature_checker checker (4);
|
||||
|
||||
auto signature_checker_work_func = [&checker] () {
|
||||
nano::keypair key;
|
||||
nano::block_builder builder;
|
||||
auto block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
auto block_hash = block->hash ();
|
||||
|
||||
auto invalid_block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
invalid_block->signature.bytes[31] ^= 0x1;
|
||||
auto invalid_block_hash = block->hash ();
|
||||
|
||||
constexpr auto num_check_sizes = 18;
|
||||
constexpr std::array<size_t, num_check_sizes> check_sizes{ 2048, 256, 1024, 1,
|
||||
4096, 512, 2050, 1024, 8092, 513, 17, 1024, 2047, 255, 513, 2049, 1025, 1023 };
|
||||
|
||||
std::vector<nano::signature_check_set> signature_checker_sets;
|
||||
signature_checker_sets.reserve (num_check_sizes);
|
||||
|
||||
// Create containers so everything is kept in scope while the threads work on the signature checks
|
||||
std::array<std::vector<unsigned char const *>, num_check_sizes> messages;
|
||||
std::array<std::vector<size_t>, num_check_sizes> lengths;
|
||||
std::array<std::vector<unsigned char const *>, num_check_sizes> pub_keys;
|
||||
std::array<std::vector<unsigned char const *>, num_check_sizes> signatures;
|
||||
std::array<std::vector<int>, num_check_sizes> verifications;
|
||||
|
||||
// Populate all the signature check sets. The last one in each set is given an incorrect block signature.
|
||||
for (int i = 0; i < num_check_sizes; ++i)
|
||||
{
|
||||
auto check_size = check_sizes[i];
|
||||
ASSERT_GT (check_size, 0);
|
||||
auto last_signature_index = check_size - 1;
|
||||
|
||||
messages[i].resize (check_size);
|
||||
std::fill (messages[i].begin (), messages[i].end (), block_hash.bytes.data ());
|
||||
messages[i][last_signature_index] = invalid_block_hash.bytes.data ();
|
||||
|
||||
lengths[i].resize (check_size);
|
||||
std::fill (lengths[i].begin (), lengths[i].end (), sizeof (decltype (block_hash)));
|
||||
|
||||
pub_keys[i].resize (check_size);
|
||||
std::fill (pub_keys[i].begin (), pub_keys[i].end (), block->hashables.account.bytes.data ());
|
||||
pub_keys[i][last_signature_index] = invalid_block->hashables.account.bytes.data ();
|
||||
|
||||
signatures[i].resize (check_size);
|
||||
std::fill (signatures[i].begin (), signatures[i].end (), block->signature.bytes.data ());
|
||||
signatures[i][last_signature_index] = invalid_block->signature.bytes.data ();
|
||||
|
||||
verifications[i].resize (check_size);
|
||||
|
||||
signature_checker_sets.emplace_back (check_size, messages[i].data (), lengths[i].data (), pub_keys[i].data (), signatures[i].data (), verifications[i].data ());
|
||||
checker.verify (signature_checker_sets[i]);
|
||||
|
||||
// Confirm all but last are valid
|
||||
auto all_valid = std::all_of (verifications[i].cbegin (), verifications[i].cend () - 1, [] (auto verification) { return verification == 1; });
|
||||
ASSERT_TRUE (all_valid);
|
||||
ASSERT_EQ (verifications[i][last_signature_index], 0);
|
||||
}
|
||||
};
|
||||
|
||||
std::thread signature_checker_thread1 (signature_checker_work_func);
|
||||
std::thread signature_checker_thread2 (signature_checker_work_func);
|
||||
|
||||
signature_checker_thread1.join ();
|
||||
signature_checker_thread2.join ();
|
||||
}
|
||||
|
||||
TEST (signature_checker, one)
|
||||
{
|
||||
nano::signature_checker checker (0);
|
||||
|
||||
auto verify_block = [&checker] (auto & block, auto result) {
|
||||
std::vector<nano::uint256_union> hashes;
|
||||
std::vector<unsigned char const *> messages;
|
||||
std::vector<size_t> lengths;
|
||||
std::vector<unsigned char const *> pub_keys;
|
||||
std::vector<unsigned char const *> signatures;
|
||||
std::vector<int> verifications;
|
||||
size_t size (1);
|
||||
verifications.resize (size);
|
||||
for (auto i (0); i < size; ++i)
|
||||
{
|
||||
hashes.push_back (block->hash ());
|
||||
messages.push_back (hashes.back ().bytes.data ());
|
||||
lengths.push_back (sizeof (decltype (hashes)::value_type));
|
||||
pub_keys.push_back (block->hashables.account.bytes.data ());
|
||||
signatures.push_back (block->signature.bytes.data ());
|
||||
}
|
||||
nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data () };
|
||||
checker.verify (check);
|
||||
ASSERT_EQ (verifications.front (), result);
|
||||
};
|
||||
|
||||
nano::keypair key;
|
||||
nano::block_builder builder;
|
||||
auto block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
|
||||
// Make signaure invalid and check result is incorrect
|
||||
block->signature.bytes[31] ^= 0x1;
|
||||
verify_block (block, 0);
|
||||
|
||||
// Make it valid and check for succcess
|
||||
block->signature.bytes[31] ^= 0x1;
|
||||
verify_block (block, 1);
|
||||
}
|
||||
|
||||
TEST (signature_checker, boundary_checks)
|
||||
{
|
||||
// sizes container must be in incrementing order
|
||||
std::vector<size_t> sizes{ 0, 1 };
|
||||
auto add_boundary = [&sizes] (size_t boundary) {
|
||||
sizes.insert (sizes.end (), { boundary - 1, boundary, boundary + 1 });
|
||||
};
|
||||
|
||||
for (auto i = 1; i <= 5; ++i)
|
||||
{
|
||||
add_boundary (nano::signature_checker::batch_size * i);
|
||||
}
|
||||
|
||||
nano::signature_checker checker (1);
|
||||
auto max_size = *(sizes.end () - 1);
|
||||
std::vector<nano::uint256_union> hashes;
|
||||
hashes.reserve (max_size);
|
||||
std::vector<unsigned char const *> messages;
|
||||
messages.reserve (max_size);
|
||||
std::vector<size_t> lengths;
|
||||
lengths.reserve (max_size);
|
||||
std::vector<unsigned char const *> pub_keys;
|
||||
pub_keys.reserve (max_size);
|
||||
std::vector<unsigned char const *> signatures;
|
||||
signatures.reserve (max_size);
|
||||
nano::keypair key;
|
||||
nano::block_builder builder;
|
||||
auto block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
|
||||
size_t last_size = 0;
|
||||
for (auto size : sizes)
|
||||
{
|
||||
// The size needed to append to existing containers, saves re-initializing from scratch each iteration
|
||||
auto extra_size = size - last_size;
|
||||
|
||||
std::vector<int> verifications;
|
||||
verifications.resize (size);
|
||||
for (auto i (0); i < extra_size; ++i)
|
||||
{
|
||||
hashes.push_back (block->hash ());
|
||||
messages.push_back (hashes.back ().bytes.data ());
|
||||
lengths.push_back (sizeof (decltype (hashes)::value_type));
|
||||
pub_keys.push_back (block->hashables.account.bytes.data ());
|
||||
signatures.push_back (block->signature.bytes.data ());
|
||||
}
|
||||
nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data () };
|
||||
checker.verify (check);
|
||||
bool all_valid = std::all_of (verifications.cbegin (), verifications.cend (), [] (auto verification) { return verification == 1; });
|
||||
ASSERT_TRUE (all_valid);
|
||||
last_size = size;
|
||||
}
|
||||
}
|
||||
|
|
@ -428,15 +428,6 @@ bool nano::validate_message (nano::public_key const & public_key, nano::uint256_
|
|||
return validate_message (public_key, message.bytes.data (), sizeof (message.bytes), signature);
|
||||
}
|
||||
|
||||
bool nano::validate_message_batch (const unsigned char ** m, size_t * mlen, const unsigned char ** pk, const unsigned char ** RS, size_t num, int * valid)
|
||||
{
|
||||
for (size_t i{ 0 }; i < num; ++i)
|
||||
{
|
||||
valid[i] = (0 == ed25519_sign_open (m[i], mlen[i], pk[i], RS[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nano::uint128_union::uint128_union (std::string const & string_a)
|
||||
{
|
||||
auto error (decode_hex (string_a));
|
||||
|
|
|
|||
|
|
@ -257,7 +257,6 @@ nano::signature sign_message (nano::raw_key const &, nano::public_key const &, n
|
|||
nano::signature sign_message (nano::raw_key const &, nano::public_key const &, uint8_t const *, size_t);
|
||||
bool validate_message (nano::public_key const &, nano::uint256_union const &, nano::signature const &);
|
||||
bool validate_message (nano::public_key const &, uint8_t const *, size_t, nano::signature const &);
|
||||
bool validate_message_batch (unsigned char const **, size_t *, unsigned char const **, unsigned char const **, size_t, int *);
|
||||
nano::raw_key deterministic_key (nano::raw_key const &, uint32_t);
|
||||
nano::public_key pub_key (nano::raw_key const &);
|
||||
|
||||
|
|
|
|||
|
|
@ -854,23 +854,6 @@ int main (int argc, char * const * argv)
|
|||
auto end (std::chrono::high_resolution_clock::now ());
|
||||
std::cerr << "Signature verifications " << std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count () << std::endl;
|
||||
}
|
||||
else if (vm.count ("debug_verify_profile_batch"))
|
||||
{
|
||||
nano::keypair key;
|
||||
size_t batch_count (1000);
|
||||
nano::uint256_union message;
|
||||
nano::uint512_union signature (nano::sign_message (key.prv, key.pub, message));
|
||||
std::vector<unsigned char const *> messages (batch_count, message.bytes.data ());
|
||||
std::vector<size_t> lengths (batch_count, sizeof (message));
|
||||
std::vector<unsigned char const *> pub_keys (batch_count, key.pub.bytes.data ());
|
||||
std::vector<unsigned char const *> signatures (batch_count, signature.bytes.data ());
|
||||
std::vector<int> verifications;
|
||||
verifications.resize (batch_count);
|
||||
auto begin (std::chrono::high_resolution_clock::now ());
|
||||
nano::validate_message_batch (messages.data (), lengths.data (), pub_keys.data (), signatures.data (), batch_count, verifications.data ());
|
||||
auto end (std::chrono::high_resolution_clock::now ());
|
||||
std::cerr << "Batch signature verifications " << std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count () << std::endl;
|
||||
}
|
||||
else if (vm.count ("debug_profile_sign"))
|
||||
{
|
||||
std::cerr << "Starting blocks signing profiling\n";
|
||||
|
|
|
|||
|
|
@ -156,10 +156,6 @@ add_library(
|
|||
scheduler/optimistic.cpp
|
||||
scheduler/priority.hpp
|
||||
scheduler/priority.cpp
|
||||
signatures.hpp
|
||||
signatures.cpp
|
||||
state_block_signature_verification.hpp
|
||||
state_block_signature_verification.cpp
|
||||
telemetry.hpp
|
||||
telemetry.cpp
|
||||
transport/channel.hpp
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
nano::block_processor::block_processor (nano::node & node_a, nano::write_database_queue & write_database_queue_a) :
|
||||
next_log (std::chrono::steady_clock::now ()),
|
||||
node (node_a),
|
||||
write_database_queue (write_database_queue_a),
|
||||
state_block_signature_verification (node.checker, node.ledger.constants.epochs, node.config, node.logger, node.flags.block_processor_verification_size)
|
||||
write_database_queue (write_database_queue_a)
|
||||
{
|
||||
batch_processed.add ([this] (auto const & items) {
|
||||
// For every batch item: notify the 'processed' observer.
|
||||
|
|
@ -21,19 +20,6 @@ nano::block_processor::block_processor (nano::node & node_a, nano::write_databas
|
|||
}
|
||||
});
|
||||
blocking.connect (*this);
|
||||
state_block_signature_verification.blocks_verified_callback = [this] (std::deque<nano::state_block_signature_verification::value_type> & items, std::vector<int> const & verifications, std::vector<nano::block_hash> const & hashes, std::vector<nano::signature> const & blocks_signatures) {
|
||||
this->process_verified_state_blocks (items, verifications, hashes, blocks_signatures);
|
||||
};
|
||||
state_block_signature_verification.transition_inactive_callback = [this] () {
|
||||
if (this->flushing)
|
||||
{
|
||||
{
|
||||
// Prevent a race with condition.wait in block_processor::flush
|
||||
nano::lock_guard<nano::mutex> guard{ this->mutex };
|
||||
}
|
||||
this->condition.notify_all ();
|
||||
}
|
||||
};
|
||||
processing_thread = std::thread ([this] () {
|
||||
nano::thread_role::set (nano::thread_role::name::block_processing);
|
||||
this->process_blocks ();
|
||||
|
|
@ -48,16 +34,14 @@ void nano::block_processor::stop ()
|
|||
}
|
||||
condition.notify_all ();
|
||||
blocking.stop ();
|
||||
state_block_signature_verification.stop ();
|
||||
nano::join_or_pass (processing_thread);
|
||||
}
|
||||
|
||||
void nano::block_processor::flush ()
|
||||
{
|
||||
node.checker.flush ();
|
||||
flushing = true;
|
||||
nano::unique_lock<nano::mutex> lock{ mutex };
|
||||
while (!stopped && (have_blocks () || active || state_block_signature_verification.is_active ()))
|
||||
while (!stopped && (have_blocks () || active))
|
||||
{
|
||||
condition.wait (lock);
|
||||
}
|
||||
|
|
@ -67,7 +51,7 @@ void nano::block_processor::flush ()
|
|||
std::size_t nano::block_processor::size ()
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lock{ mutex };
|
||||
return (blocks.size () + state_block_signature_verification.size () + forced.size ());
|
||||
return blocks.size () + forced.size ();
|
||||
}
|
||||
|
||||
bool nano::block_processor::full ()
|
||||
|
|
@ -207,40 +191,7 @@ bool nano::block_processor::have_blocks_ready ()
|
|||
bool nano::block_processor::have_blocks ()
|
||||
{
|
||||
debug_assert (!mutex.try_lock ());
|
||||
return have_blocks_ready () || state_block_signature_verification.size () != 0;
|
||||
}
|
||||
|
||||
void nano::block_processor::process_verified_state_blocks (std::deque<nano::state_block_signature_verification::value_type> & items, std::vector<int> const & verifications, std::vector<nano::block_hash> const & hashes, std::vector<nano::signature> const & blocks_signatures)
|
||||
{
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lk{ mutex };
|
||||
for (auto i (0); i < verifications.size (); ++i)
|
||||
{
|
||||
debug_assert (verifications[i] == 1 || verifications[i] == 0);
|
||||
auto & item = items.front ();
|
||||
auto & [block] = item;
|
||||
if (!block->link ().is_zero () && node.ledger.is_epoch_link (block->link ()))
|
||||
{
|
||||
// Epoch blocks
|
||||
if (verifications[i] == 1)
|
||||
{
|
||||
blocks.emplace_back (block);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Possible regular state blocks with epoch link (send subtype)
|
||||
blocks.emplace_back (block);
|
||||
}
|
||||
}
|
||||
else if (verifications[i] == 1)
|
||||
{
|
||||
// Non epoch blocks
|
||||
blocks.emplace_back (block);
|
||||
}
|
||||
items.pop_front ();
|
||||
}
|
||||
}
|
||||
condition.notify_all ();
|
||||
return have_blocks_ready ();
|
||||
}
|
||||
|
||||
void nano::block_processor::add_impl (std::shared_ptr<nano::block> block)
|
||||
|
|
@ -267,9 +218,9 @@ auto nano::block_processor::process_batch (nano::unique_lock<nano::mutex> & lock
|
|||
auto store_batch_reached = [&number_of_blocks_processed, max = node.store.max_block_write_batch_num ()] { return number_of_blocks_processed >= max; };
|
||||
while (have_blocks_ready () && (!deadline_reached () || !processor_batch_reached ()) && !store_batch_reached ())
|
||||
{
|
||||
if ((blocks.size () + state_block_signature_verification.size () + forced.size () > 64) && should_log ())
|
||||
if ((blocks.size () + forced.size () > 64) && should_log ())
|
||||
{
|
||||
node.logger.always_log (boost::str (boost::format ("%1% blocks (+ %2% state blocks) (+ %3% forced) in processing queue") % blocks.size () % state_block_signature_verification.size () % forced.size ()));
|
||||
node.logger.always_log (boost::str (boost::format ("%1% blocks (+ %2% forced) in processing queue") % blocks.size () % forced.size ()));
|
||||
}
|
||||
std::shared_ptr<nano::block> block;
|
||||
nano::block_hash hash (0);
|
||||
|
|
@ -471,7 +422,6 @@ std::unique_ptr<nano::container_info_component> nano::collect_container_info (bl
|
|||
}
|
||||
|
||||
auto composite = std::make_unique<container_info_composite> (name);
|
||||
composite->add_component (collect_container_info (block_processor.state_block_signature_verification, "state_block_signature_verification"));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "blocks", blocks_count, sizeof (decltype (block_processor.blocks)::value_type) }));
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "forced", forced_count, sizeof (decltype (block_processor.forced)::value_type) }));
|
||||
return composite;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/node/blocking_observer.hpp>
|
||||
#include <nano/node/state_block_signature_verification.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
|
@ -59,7 +58,6 @@ private:
|
|||
nano::process_return process_one (store::write_transaction const &, std::shared_ptr<nano::block> block, bool const = false);
|
||||
void queue_unchecked (store::write_transaction const &, nano::hash_or_account const &);
|
||||
std::deque<processed_t> process_batch (nano::unique_lock<nano::mutex> &);
|
||||
void process_verified_state_blocks (std::deque<nano::state_block_signature_verification::value_type> &, std::vector<int> const &, std::vector<nano::block_hash> const &, std::vector<nano::signature> const &);
|
||||
void add_impl (std::shared_ptr<nano::block> block);
|
||||
bool stopped{ false };
|
||||
bool active{ false };
|
||||
|
|
@ -70,7 +68,6 @@ private:
|
|||
nano::node & node;
|
||||
nano::write_database_queue & write_database_queue;
|
||||
nano::mutex mutex{ mutex_identifier (mutexes::block_processor) };
|
||||
nano::state_block_signature_verification state_block_signature_verification;
|
||||
std::thread processing_thread;
|
||||
|
||||
friend std::unique_ptr<container_info_component> collect_container_info (block_processor & block_processor, std::string const & name);
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ nano::node::node (boost::asio::io_context & io_ctx_a, std::filesystem::path cons
|
|||
wallets_store (*wallets_store_impl),
|
||||
gap_cache (*this),
|
||||
ledger (store, stats, network_params.ledger, flags_a.generate_cache),
|
||||
checker (config.signature_checker_threads),
|
||||
outbound_limiter{ outbound_bandwidth_limiter_config (config) },
|
||||
// empty `config.peering_port` means the user made no port choice at all;
|
||||
// otherwise, any value is considered, with `0` having the special meaning of 'let the OS pick a port instead'
|
||||
|
|
@ -728,7 +727,6 @@ void nano::node::stop ()
|
|||
bootstrap_initiator.stop ();
|
||||
tcp_listener.stop ();
|
||||
port_mapping.stop ();
|
||||
checker.stop ();
|
||||
wallets.stop ();
|
||||
stats.stop ();
|
||||
epoch_upgrader.stop ();
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include <nano/node/process_live_dispatcher.hpp>
|
||||
#include <nano/node/repcrawler.hpp>
|
||||
#include <nano/node/request_aggregator.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
#include <nano/node/telemetry.hpp>
|
||||
#include <nano/node/transport/tcp_server.hpp>
|
||||
#include <nano/node/unchecked_map.hpp>
|
||||
|
|
@ -159,7 +158,6 @@ public:
|
|||
nano::wallets_store & wallets_store;
|
||||
nano::gap_cache gap_cache;
|
||||
nano::ledger ledger;
|
||||
nano::signature_checker checker;
|
||||
nano::outbound_bandwidth_limiter outbound_limiter;
|
||||
nano::network network;
|
||||
nano::telemetry telemetry;
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
#include <nano/boost/asio/post.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
|
||||
nano::signature_checker::signature_checker (unsigned num_threads) :
|
||||
thread_pool (num_threads, nano::thread_role::name::signature_checking)
|
||||
{
|
||||
}
|
||||
|
||||
nano::signature_checker::~signature_checker ()
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
void nano::signature_checker::verify (nano::signature_check_set & check_a)
|
||||
{
|
||||
// Don't process anything else if we have stopped
|
||||
if (stopped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_a.size <= batch_size || single_threaded ())
|
||||
{
|
||||
// Not dealing with many so just use the calling thread for checking signatures
|
||||
auto result = verify_batch (check_a, 0, check_a.size);
|
||||
release_assert (result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Split up the tasks equally over the calling thread and the thread pool.
|
||||
// Any overflow on the modulus of the batch_size is given to the calling thread, so the thread pool
|
||||
// only ever operates on batch_size sizes.
|
||||
std::size_t overflow_size = check_a.size % batch_size;
|
||||
std::size_t num_full_batches = check_a.size / batch_size;
|
||||
|
||||
auto const num_threads = thread_pool.get_num_threads ();
|
||||
auto total_threads_to_split_over = num_threads + 1;
|
||||
auto num_base_batches_each = num_full_batches / total_threads_to_split_over;
|
||||
auto num_full_overflow_batches = num_full_batches % total_threads_to_split_over;
|
||||
|
||||
auto size_calling_thread = (num_base_batches_each * batch_size) + overflow_size;
|
||||
auto num_full_batches_thread = (num_base_batches_each * num_threads);
|
||||
if (num_full_overflow_batches > 0)
|
||||
{
|
||||
if (overflow_size == 0)
|
||||
{
|
||||
// Give the calling thread priority over any batches when there is no excess remainder.
|
||||
size_calling_thread += batch_size;
|
||||
num_full_batches_thread += num_full_overflow_batches - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
num_full_batches_thread += num_full_overflow_batches;
|
||||
}
|
||||
}
|
||||
|
||||
release_assert (check_a.size == (num_full_batches_thread * batch_size + size_calling_thread));
|
||||
|
||||
std::promise<void> promise;
|
||||
std::future<void> future = promise.get_future ();
|
||||
|
||||
// Verify a number of signature batches over the thread pool (does not block)
|
||||
verify_async (check_a, num_full_batches_thread, promise);
|
||||
|
||||
// Verify the rest on the calling thread, this operates on the signatures at the end of the check set
|
||||
auto result = verify_batch (check_a, check_a.size - size_calling_thread, size_calling_thread);
|
||||
release_assert (result);
|
||||
|
||||
// Blocks until all the work is done
|
||||
future.wait ();
|
||||
}
|
||||
|
||||
void nano::signature_checker::stop ()
|
||||
{
|
||||
if (!stopped.exchange (true))
|
||||
{
|
||||
thread_pool.stop ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::signature_checker::flush ()
|
||||
{
|
||||
while (!stopped && tasks_remaining != 0)
|
||||
;
|
||||
}
|
||||
|
||||
bool nano::signature_checker::verify_batch (nano::signature_check_set const & check_a, std::size_t start_index, std::size_t size)
|
||||
{
|
||||
nano::validate_message_batch (check_a.messages + start_index, check_a.message_lengths + start_index, check_a.pub_keys + start_index, check_a.signatures + start_index, size, check_a.verifications + start_index);
|
||||
return std::all_of (check_a.verifications + start_index, check_a.verifications + start_index + size, [] (int verification) { return verification == 0 || verification == 1; });
|
||||
}
|
||||
|
||||
/* This operates on a number of signatures of size (num_batches * batch_size) from the beginning of the check_a pointers.
|
||||
* Caller should check the value of the promise which indicates when the work has been completed.
|
||||
*/
|
||||
void nano::signature_checker::verify_async (nano::signature_check_set & check_a, std::size_t num_batches, std::promise<void> & promise)
|
||||
{
|
||||
auto task = std::make_shared<Task> (check_a, num_batches);
|
||||
++tasks_remaining;
|
||||
|
||||
for (std::size_t batch = 0; batch < num_batches; ++batch)
|
||||
{
|
||||
auto size = batch_size;
|
||||
auto start_index = batch * batch_size;
|
||||
|
||||
thread_pool.push_task ([this, task, size, start_index, &promise] {
|
||||
auto result = this->verify_batch (task->check, start_index, size);
|
||||
release_assert (result);
|
||||
|
||||
if (--task->pending == 0)
|
||||
{
|
||||
--tasks_remaining;
|
||||
promise.set_value ();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool nano::signature_checker::single_threaded () const
|
||||
{
|
||||
return thread_pool.get_num_threads () == 0;
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/thread_pool.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class signature_check_set final
|
||||
{
|
||||
public:
|
||||
signature_check_set (std::size_t size, unsigned char const ** messages, std::size_t * message_lengths, unsigned char const ** pub_keys, unsigned char const ** signatures, int * verifications) :
|
||||
size (size), messages (messages), message_lengths (message_lengths), pub_keys (pub_keys), signatures (signatures), verifications (verifications)
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t size;
|
||||
unsigned char const ** messages;
|
||||
std::size_t * message_lengths;
|
||||
unsigned char const ** pub_keys;
|
||||
unsigned char const ** signatures;
|
||||
int * verifications;
|
||||
};
|
||||
|
||||
/** Multi-threaded signature checker */
|
||||
class signature_checker final
|
||||
{
|
||||
public:
|
||||
signature_checker (unsigned num_threads);
|
||||
~signature_checker ();
|
||||
void verify (signature_check_set &);
|
||||
void stop ();
|
||||
void flush ();
|
||||
|
||||
static std::size_t constexpr batch_size = 256;
|
||||
|
||||
private:
|
||||
std::atomic<int> tasks_remaining{ 0 };
|
||||
std::atomic<bool> stopped{ false };
|
||||
nano::thread_pool thread_pool;
|
||||
|
||||
struct Task final
|
||||
{
|
||||
Task (nano::signature_check_set & check, std::size_t pending) :
|
||||
check (check), pending (pending)
|
||||
{
|
||||
}
|
||||
~Task ()
|
||||
{
|
||||
release_assert (pending == 0);
|
||||
}
|
||||
nano::signature_check_set & check;
|
||||
std::atomic<std::size_t> pending;
|
||||
};
|
||||
|
||||
bool verify_batch (nano::signature_check_set const & check_a, std::size_t index, std::size_t size);
|
||||
void verify_async (nano::signature_check_set & check_a, std::size_t num_batches, std::promise<void> & promise);
|
||||
bool single_threaded () const;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
#include <nano/lib/logger_mt.hpp>
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/node/nodeconfig.hpp>
|
||||
#include <nano/node/signatures.hpp>
|
||||
#include <nano/node/state_block_signature_verification.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
nano::state_block_signature_verification::state_block_signature_verification (nano::signature_checker & signature_checker, nano::epochs & epochs, nano::node_config & node_config, nano::logger_mt & logger, uint64_t state_block_signature_verification_size) :
|
||||
signature_checker (signature_checker),
|
||||
epochs (epochs),
|
||||
node_config (node_config),
|
||||
logger (logger),
|
||||
thread ([this, state_block_signature_verification_size] () {
|
||||
nano::thread_role::set (nano::thread_role::name::state_block_signature_verification);
|
||||
this->run (state_block_signature_verification_size);
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
nano::state_block_signature_verification::~state_block_signature_verification ()
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
|
||||
void nano::state_block_signature_verification::stop ()
|
||||
{
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
if (thread.joinable ())
|
||||
{
|
||||
condition.notify_one ();
|
||||
thread.join ();
|
||||
}
|
||||
}
|
||||
|
||||
void nano::state_block_signature_verification::run (uint64_t state_block_signature_verification_size)
|
||||
{
|
||||
nano::unique_lock<nano::mutex> lk (mutex);
|
||||
while (!stopped)
|
||||
{
|
||||
if (!state_blocks.empty ())
|
||||
{
|
||||
std::size_t const max_verification_batch (state_block_signature_verification_size != 0 ? state_block_signature_verification_size : nano::signature_checker::batch_size * (node_config.signature_checker_threads + 1));
|
||||
active = true;
|
||||
while (!state_blocks.empty () && !stopped)
|
||||
{
|
||||
auto items = setup_items (max_verification_batch);
|
||||
lk.unlock ();
|
||||
verify_state_blocks (items);
|
||||
lk.lock ();
|
||||
}
|
||||
active = false;
|
||||
lk.unlock ();
|
||||
transition_inactive_callback ();
|
||||
lk.lock ();
|
||||
}
|
||||
else
|
||||
{
|
||||
condition.wait (lk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nano::state_block_signature_verification::is_active ()
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
return active;
|
||||
}
|
||||
|
||||
void nano::state_block_signature_verification::add (value_type const & item)
|
||||
{
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
state_blocks.emplace_back (item);
|
||||
}
|
||||
condition.notify_one ();
|
||||
}
|
||||
|
||||
std::size_t nano::state_block_signature_verification::size ()
|
||||
{
|
||||
nano::lock_guard<nano::mutex> guard (mutex);
|
||||
return state_blocks.size ();
|
||||
}
|
||||
|
||||
auto nano::state_block_signature_verification::setup_items (std::size_t max_count) -> std::deque<value_type>
|
||||
{
|
||||
std::deque<value_type> items;
|
||||
if (state_blocks.size () <= max_count)
|
||||
{
|
||||
items.swap (state_blocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i (0); i < max_count; ++i)
|
||||
{
|
||||
items.push_back (state_blocks.front ());
|
||||
state_blocks.pop_front ();
|
||||
}
|
||||
debug_assert (!state_blocks.empty ());
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void nano::state_block_signature_verification::verify_state_blocks (std::deque<value_type> & items)
|
||||
{
|
||||
if (!items.empty ())
|
||||
{
|
||||
nano::timer<> timer_l;
|
||||
timer_l.start ();
|
||||
auto size (items.size ());
|
||||
std::vector<nano::block_hash> hashes;
|
||||
hashes.reserve (size);
|
||||
std::vector<unsigned char const *> messages;
|
||||
messages.reserve (size);
|
||||
std::vector<std::size_t> lengths;
|
||||
lengths.reserve (size);
|
||||
std::vector<nano::account> accounts;
|
||||
accounts.reserve (size);
|
||||
std::vector<unsigned char const *> pub_keys;
|
||||
pub_keys.reserve (size);
|
||||
std::vector<nano::signature> blocks_signatures;
|
||||
blocks_signatures.reserve (size);
|
||||
std::vector<unsigned char const *> signatures;
|
||||
signatures.reserve (size);
|
||||
std::vector<int> verifications;
|
||||
verifications.resize (size, 0);
|
||||
for (auto const & [block] : items)
|
||||
{
|
||||
hashes.push_back (block->hash ());
|
||||
messages.push_back (hashes.back ().bytes.data ());
|
||||
lengths.push_back (sizeof (decltype (hashes)::value_type));
|
||||
nano::account account_l = block->account ();
|
||||
if (!block->link ().is_zero () && epochs.is_epoch_link (block->link ()))
|
||||
{
|
||||
account_l = epochs.signer (epochs.epoch (block->link ()));
|
||||
}
|
||||
accounts.push_back (account_l);
|
||||
pub_keys.push_back (accounts.back ().bytes.data ());
|
||||
blocks_signatures.push_back (block->block_signature ());
|
||||
signatures.push_back (blocks_signatures.back ().bytes.data ());
|
||||
}
|
||||
nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data () };
|
||||
signature_checker.verify (check);
|
||||
if (node_config.logging.timing_logging () && timer_l.stop () > std::chrono::milliseconds (10))
|
||||
{
|
||||
logger.try_log (boost::str (boost::format ("Batch verified %1% state blocks in %2% %3%") % size % timer_l.value ().count () % timer_l.unit ()));
|
||||
}
|
||||
blocks_verified_callback (items, verifications, hashes, blocks_signatures);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<nano::container_info_component> nano::collect_container_info (state_block_signature_verification & state_block_signature_verification, std::string const & name)
|
||||
{
|
||||
auto composite = std::make_unique<container_info_composite> (name);
|
||||
composite->add_component (std::make_unique<container_info_leaf> (container_info{ "state_blocks", state_block_signature_verification.size (), sizeof (state_block_signature_verification::value_type) }));
|
||||
return composite;
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class epochs;
|
||||
class logger_mt;
|
||||
class node_config;
|
||||
class signature_checker;
|
||||
|
||||
class state_block_signature_verification
|
||||
{
|
||||
public:
|
||||
using value_type = std::tuple<std::shared_ptr<nano::block>>;
|
||||
|
||||
state_block_signature_verification (nano::signature_checker &, nano::epochs &, nano::node_config &, nano::logger_mt &, uint64_t);
|
||||
~state_block_signature_verification ();
|
||||
void add (value_type const & item);
|
||||
std::size_t size ();
|
||||
void stop ();
|
||||
bool is_active ();
|
||||
|
||||
std::function<void (std::deque<value_type> &, std::vector<int> const &, std::vector<nano::block_hash> const &, std::vector<nano::signature> const &)> blocks_verified_callback;
|
||||
std::function<void ()> transition_inactive_callback;
|
||||
|
||||
private:
|
||||
nano::signature_checker & signature_checker;
|
||||
nano::epochs & epochs;
|
||||
nano::node_config & node_config;
|
||||
nano::logger_mt & logger;
|
||||
|
||||
nano::mutex mutex{ mutex_identifier (mutexes::state_block_signature_verification) };
|
||||
bool stopped{ false };
|
||||
bool active{ false };
|
||||
std::deque<value_type> state_blocks;
|
||||
nano::condition_variable condition;
|
||||
std::thread thread;
|
||||
|
||||
void run (uint64_t block_processor_verification_size);
|
||||
std::deque<value_type> setup_items (std::size_t);
|
||||
void verify_state_blocks (std::deque<value_type> &);
|
||||
};
|
||||
|
||||
std::unique_ptr<nano::container_info_component> collect_container_info (state_block_signature_verification & state_block_signature_verification, std::string const & name);
|
||||
}
|
||||
|
|
@ -1739,72 +1739,6 @@ TEST (telemetry, many_nodes)
|
|||
ASSERT_FALSE (all_bandwidth_limits_same);
|
||||
}
|
||||
|
||||
// Similar to signature_checker.boundary_checks but more exhaustive. Can take up to 1 minute
|
||||
TEST (signature_checker, mass_boundary_checks)
|
||||
{
|
||||
// sizes container must be in incrementing order
|
||||
std::vector<size_t> sizes{ 0, 1 };
|
||||
auto add_boundary = [&sizes] (size_t boundary) {
|
||||
sizes.insert (sizes.end (), { boundary - 1, boundary, boundary + 1 });
|
||||
};
|
||||
|
||||
for (auto i = 1; i <= 10; ++i)
|
||||
{
|
||||
add_boundary (nano::signature_checker::batch_size * i);
|
||||
}
|
||||
|
||||
nano::block_builder builder;
|
||||
for (auto num_threads = 0; num_threads < 5; ++num_threads)
|
||||
{
|
||||
nano::signature_checker checker (num_threads);
|
||||
auto max_size = *(sizes.end () - 1);
|
||||
std::vector<nano::uint256_union> hashes;
|
||||
hashes.reserve (max_size);
|
||||
std::vector<unsigned char const *> messages;
|
||||
messages.reserve (max_size);
|
||||
std::vector<size_t> lengths;
|
||||
lengths.reserve (max_size);
|
||||
std::vector<unsigned char const *> pub_keys;
|
||||
pub_keys.reserve (max_size);
|
||||
std::vector<unsigned char const *> signatures;
|
||||
signatures.reserve (max_size);
|
||||
nano::keypair key;
|
||||
auto block = builder
|
||||
.state ()
|
||||
.account (key.pub)
|
||||
.previous (0)
|
||||
.representative (key.pub)
|
||||
.balance (0)
|
||||
.link (0)
|
||||
.sign (key.prv, key.pub)
|
||||
.work (0)
|
||||
.build ();
|
||||
|
||||
size_t last_size = 0;
|
||||
for (auto size : sizes)
|
||||
{
|
||||
// The size needed to append to existing containers, saves re-initializing from scratch each iteration
|
||||
auto extra_size = size - last_size;
|
||||
|
||||
std::vector<int> verifications;
|
||||
verifications.resize (size);
|
||||
for (auto i (0); i < extra_size; ++i)
|
||||
{
|
||||
hashes.push_back (block->hash ());
|
||||
messages.push_back (hashes.back ().bytes.data ());
|
||||
lengths.push_back (sizeof (decltype (hashes)::value_type));
|
||||
pub_keys.push_back (block->hashables.account.bytes.data ());
|
||||
signatures.push_back (block->signature.bytes.data ());
|
||||
}
|
||||
nano::signature_check_set check = { size, messages.data (), lengths.data (), pub_keys.data (), signatures.data (), verifications.data () };
|
||||
checker.verify (check);
|
||||
bool all_valid = std::all_of (verifications.cbegin (), verifications.cend (), [] (auto verification) { return verification == 1; });
|
||||
ASSERT_TRUE (all_valid);
|
||||
last_size = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test the node epoch_upgrader with a large number of accounts and threads
|
||||
// Possible to manually add work peers
|
||||
TEST (node, mass_epoch_upgrader)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue