Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Larger votes preparation #4350

Merged
merged 3 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 151 additions & 1 deletion nano/core_test/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,59 @@ TEST (message, publish_serialization)
ASSERT_EQ (nano::message_type::publish, header.type);
}

TEST (message, confirm_header_flags)
{
nano::message_header header_v2{ nano::dev::network_params.network, nano::message_type::confirm_req };
header_v2.confirm_set_v2 (true);

const uint8_t value = 0b0110'1001;

header_v2.count_v2_set (value); // Max count value

ASSERT_TRUE (header_v2.confirm_is_v2 ());
ASSERT_EQ (header_v2.count_v2_get (), value);

std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
header_v2.serialize (stream);
}
nano::bufferstream stream (bytes.data (), bytes.size ());

bool error = false;
nano::message_header header (error, stream);
ASSERT_FALSE (error);
ASSERT_EQ (nano::message_type::confirm_req, header.type);

ASSERT_TRUE (header.confirm_is_v2 ());
ASSERT_EQ (header.count_v2_get (), value);
}

TEST (message, confirm_header_flags_max)
{
nano::message_header header_v2{ nano::dev::network_params.network, nano::message_type::confirm_req };
header_v2.confirm_set_v2 (true);
header_v2.count_v2_set (255); // Max count value

ASSERT_TRUE (header_v2.confirm_is_v2 ());
ASSERT_EQ (header_v2.count_v2_get (), 255);

std::vector<uint8_t> bytes;
{
nano::vectorstream stream (bytes);
header_v2.serialize (stream);
}
nano::bufferstream stream (bytes.data (), bytes.size ());

bool error = false;
nano::message_header header (error, stream);
ASSERT_FALSE (error);
ASSERT_EQ (nano::message_type::confirm_req, header.type);

ASSERT_TRUE (header.confirm_is_v2 ());
ASSERT_EQ (header.count_v2_get (), 255);
}

TEST (message, confirm_ack_hash_serialization)
{
std::vector<nano::block_hash> hashes;
Expand Down Expand Up @@ -126,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<nano::block_hash> 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<nano::vote> (representative1.pub, representative1.prv, 0, 0, hashes));
nano::confirm_ack con1{ nano::dev::network_params.network, vote };
std::vector<uint8_t> 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;
Expand Down Expand Up @@ -210,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<std::pair<nano::block_hash, nano::root>> 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<uint8_t> 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
Expand Down
27 changes: 26 additions & 1 deletion nano/core_test/vote_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ TEST (vote_processor, codes)
// Hint of pre-validation
ASSERT_NE (nano::vote_code::invalid, node.vote_processor.vote_blocking (vote_invalid, channel, true));

// No ongoing election
// No ongoing election (vote goes to vote cache)
ASSERT_EQ (nano::vote_code::indeterminate, node.vote_processor.vote_blocking (vote, channel));

// Clear vote cache before starting election
node.vote_cache.clear ();

// First vote from an account for an ongoing election
node.start_election (blocks[0]);
std::shared_ptr<nano::election> election;
Expand Down Expand Up @@ -326,6 +329,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
*/
Expand Down
Loading
Loading