diff --git a/nano/core_test/message.cpp b/nano/core_test/message.cpp index 01425492..29e70e37 100644 --- a/nano/core_test/message.cpp +++ b/nano/core_test/message.cpp @@ -179,10 +179,51 @@ TEST (message, confirm_ack_hash_serialization) ASSERT_FALSE (error); ASSERT_EQ (con1, con2); ASSERT_EQ (hashes, con2.vote->hashes); - // Check overflow with max hashes + ASSERT_FALSE (header.confirm_is_v2 ()); ASSERT_EQ (header.count_get (), hashes.size ()); } +TEST (message, confirm_ack_hash_serialization_v2) +{ + std::vector hashes; + for (auto i (hashes.size ()); i < 255; i++) + { + nano::keypair key1; + nano::block_hash previous; + nano::random_pool::generate_block (previous.bytes.data (), previous.bytes.size ()); + nano::block_builder builder; + auto block = builder + .state () + .account (key1.pub) + .previous (previous) + .representative (key1.pub) + .balance (2) + .link (4) + .sign (key1.prv, key1.pub) + .work (5) + .build (); + hashes.push_back (block->hash ()); + } + + nano::keypair representative1; + auto vote (std::make_shared (representative1.pub, representative1.prv, 0, 0, hashes)); + nano::confirm_ack con1{ nano::dev::network_params.network, vote }; + std::vector bytes; + { + nano::vectorstream stream1 (bytes); + con1.serialize (stream1); + } + nano::bufferstream stream2 (bytes.data (), bytes.size ()); + bool error (false); + nano::message_header header (error, stream2); + nano::confirm_ack con2 (error, stream2, header); + ASSERT_FALSE (error); + ASSERT_EQ (con1, con2); + ASSERT_EQ (hashes, con2.vote->hashes); + ASSERT_TRUE (header.confirm_is_v2 ()); + ASSERT_EQ (header.count_v2_get (), hashes.size ()); +} + TEST (message, confirm_req_hash_serialization) { nano::keypair key1; @@ -263,6 +304,62 @@ TEST (message, confirm_req_hash_batch_serialization) ASSERT_EQ (req.roots_hashes, roots_hashes); ASSERT_EQ (req2.roots_hashes, roots_hashes); ASSERT_EQ (header.count_get (), req.roots_hashes.size ()); + ASSERT_FALSE (header.confirm_is_v2 ()); +} + +TEST (message, confirm_req_hash_batch_serialization_v2) +{ + nano::keypair key; + nano::keypair representative; + nano::block_builder builder; + auto open = builder + .state () + .account (key.pub) + .previous (0) + .representative (representative.pub) + .balance (2) + .link (4) + .sign (key.prv, key.pub) + .work (5) + .build (); + + std::vector> roots_hashes; + roots_hashes.push_back (std::make_pair (open->hash (), open->root ())); + for (auto i (roots_hashes.size ()); i < 255; i++) + { + nano::keypair key1; + nano::block_hash previous; + nano::random_pool::generate_block (previous.bytes.data (), previous.bytes.size ()); + auto block = builder + .state () + .account (key1.pub) + .previous (previous) + .representative (representative.pub) + .balance (2) + .link (4) + .sign (key1.prv, key1.pub) + .work (5) + .build (); + roots_hashes.push_back (std::make_pair (block->hash (), block->root ())); + } + + nano::confirm_req req{ nano::dev::network_params.network, roots_hashes }; + std::vector bytes; + { + nano::vectorstream stream (bytes); + req.serialize (stream); + } + auto error (false); + nano::bufferstream stream2 (bytes.data (), bytes.size ()); + nano::message_header header (error, stream2); + nano::confirm_req req2 (error, stream2, header); + ASSERT_FALSE (error); + ASSERT_EQ (req, req2); + ASSERT_EQ (req.roots_hashes, req2.roots_hashes); + ASSERT_EQ (req.roots_hashes, roots_hashes); + ASSERT_EQ (req2.roots_hashes, roots_hashes); + ASSERT_EQ (header.count_v2_get (), req.roots_hashes.size ()); + ASSERT_TRUE (header.confirm_is_v2 ()); } // this unit test checks that conversion of message_header to string works as expected diff --git a/nano/core_test/vote_processor.cpp b/nano/core_test/vote_processor.cpp index a444719b..48bdc4ec 100644 --- a/nano/core_test/vote_processor.cpp +++ b/nano/core_test/vote_processor.cpp @@ -326,6 +326,28 @@ TEST (vote_processor, no_broadcast_local_with_a_principal_representative) ASSERT_EQ (1, node.stats.count (nano::stat::type::message, nano::stat::detail::publish, nano::stat::dir::out)); } +/** + * Ensure that node behaves well with votes larger than 12 hashes, which was maximum before V26 + */ +TEST (vote_processor, large_votes) +{ + nano::test::system system (1); + auto & node = *system.nodes[0]; + + const int count = 32; + auto blocks = nano::test::setup_chain (system, node, count, nano::dev::genesis_key, /* do not confirm */ false); + + ASSERT_TRUE (nano::test::start_elections (system, node, blocks)); + ASSERT_TIMELY (5s, nano::test::active (node, blocks)); + + auto vote = nano::test::make_final_vote (nano::dev::genesis_key, blocks); + ASSERT_TRUE (vote->hashes.size () == count); + + node.vote_processor.vote (vote, nano::test::fake_channel (node)); + + ASSERT_TIMELY (5s, nano::test::confirmed (node, blocks)); +} + /** * basic test to check that the timestamp mask is applied correctly on vote timestamp and duration fields */ diff --git a/nano/node/request_aggregator.cpp b/nano/node/request_aggregator.cpp index cb84ba60..7f6aa2d2 100644 --- a/nano/node/request_aggregator.cpp +++ b/nano/node/request_aggregator.cpp @@ -34,6 +34,7 @@ nano::request_aggregator::request_aggregator (nano::node_config const & config_a condition.wait (lock, [&started = started] { return started; }); } +// TODO: This is badly implemented, will prematurely drop large vote requests void nano::request_aggregator::add (std::shared_ptr const & channel_a, std::vector> const & hashes_roots_a) { debug_assert (wallets.reps ().voting > 0); diff --git a/nano/test_common/chains.cpp b/nano/test_common/chains.cpp index af528e92..bb77caa0 100644 --- a/nano/test_common/chains.cpp +++ b/nano/test_common/chains.cpp @@ -18,7 +18,7 @@ nano::block_list_t nano::test::setup_chain (nano::test::system & system, nano::n .state () .account (target.pub) .previous (latest) - .representative (throwaway.pub) + .representative (target.pub) .balance (balance) .link (throwaway.pub) .sign (target.prv, target.pub)