Add tests for vote_processor (#2574)

This commit is contained in:
Guilherme Lawless 2020-02-20 12:02:07 +00:00 committed by GitHub
commit ae3c3e396a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 0 deletions

View file

@ -37,6 +37,7 @@ add_executable (core_test
uint256_union.cpp
utility.cpp
versioning.cpp
vote_processor.cpp
wallet.cpp
wallets.cpp
websocket.cpp

View file

@ -0,0 +1,142 @@
#include <nano/core_test/testutil.hpp>
#include <nano/lib/jsonconfig.hpp>
#include <nano/node/testing.hpp>
#include <nano/node/vote_processor.hpp>
#include <gtest/gtest.h>
using namespace std::chrono_literals;
TEST (vote_processor, codes)
{
nano::system system (1);
auto & node (*system.nodes[0]);
nano::genesis genesis;
nano::keypair key;
auto vote (std::make_shared<nano::vote> (key.pub, key.prv, 1, std::vector<nano::block_hash>{ genesis.open->hash () }));
auto vote_invalid = std::make_shared<nano::vote> (*vote);
vote_invalid->signature.bytes[0] ^= 1;
auto channel (std::make_shared<nano::transport::channel_udp> (node.network.udp_channels, node.network.endpoint (), node.network_params.protocol.protocol_version));
// Invalid signature
ASSERT_EQ (nano::vote_code::invalid, node.vote_processor.vote_blocking (vote_invalid, channel, false));
// Hint of pre-validation
ASSERT_NE (nano::vote_code::invalid, node.vote_processor.vote_blocking (vote_invalid, channel, true));
// No ongoing election
ASSERT_EQ (nano::vote_code::indeterminate, node.vote_processor.vote_blocking (vote, channel));
// First vote from an account for an ongoing election
ASSERT_TRUE (node.active.insert (genesis.open).second);
ASSERT_EQ (nano::vote_code::vote, node.vote_processor.vote_blocking (vote, channel));
// Processing the same vote is a replay
ASSERT_EQ (nano::vote_code::replay, node.vote_processor.vote_blocking (vote, channel));
// Invalid takes precedence
ASSERT_EQ (nano::vote_code::invalid, node.vote_processor.vote_blocking (vote_invalid, channel));
// A higher sequence is not a replay
++vote->sequence;
ASSERT_EQ (nano::vote_code::invalid, node.vote_processor.vote_blocking (vote, channel));
vote->signature = nano::sign_message (key.prv, key.pub, vote->hash ());
ASSERT_EQ (nano::vote_code::vote, node.vote_processor.vote_blocking (vote, channel));
// Once the election is removed (confirmed / dropped) the vote is again indeterminate
node.active.erase (*genesis.open);
ASSERT_EQ (nano::vote_code::indeterminate, node.vote_processor.vote_blocking (vote, channel));
}
TEST (vote_processor, flush)
{
nano::system system (1);
auto & node (*system.nodes[0]);
nano::genesis genesis;
auto vote (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, std::vector<nano::block_hash>{ genesis.open->hash () }));
auto channel (std::make_shared<nano::transport::channel_udp> (node.network.udp_channels, node.network.endpoint (), node.network_params.protocol.protocol_version));
for (unsigned i = 0; i < 2000; ++i)
{
node.vote_processor.vote (vote, channel);
++vote->sequence; // invalidates votes without signing again
}
node.vote_processor.flush ();
ASSERT_TRUE (node.vote_processor.empty ());
}
TEST (vote_processor, invalid_signature)
{
nano::system system (1);
auto & node (*system.nodes[0]);
nano::genesis genesis;
nano::keypair key;
auto vote (std::make_shared<nano::vote> (key.pub, key.prv, 1, std::vector<nano::block_hash>{ genesis.open->hash () }));
auto vote_invalid = std::make_shared<nano::vote> (*vote);
vote_invalid->signature.bytes[0] ^= 1;
auto channel (std::make_shared<nano::transport::channel_udp> (node.network.udp_channels, node.network.endpoint (), node.network_params.protocol.protocol_version));
auto election (node.active.insert (genesis.open));
ASSERT_TRUE (election.first && election.second);
ASSERT_EQ (1, election.first->last_votes.size ());
node.vote_processor.vote (vote_invalid, channel);
node.vote_processor.flush ();
ASSERT_EQ (1, election.first->last_votes.size ());
node.vote_processor.vote (vote, channel);
node.vote_processor.flush ();
ASSERT_EQ (2, election.first->last_votes.size ());
}
namespace nano
{
TEST (vote_processor, weights)
{
nano::system system (4);
auto & node (*system.nodes[0]);
// Create representatives of different weight levels
// The online stake will be the minimum configurable due to online_reps sampling in tests
auto const online = node.config.online_weight_minimum.number ();
auto const level0 = online / 5000; // 0.02%
auto const level1 = online / 500; // 0.2%
auto const level2 = online / 50; // 2%
nano::keypair key0;
nano::keypair key1;
nano::keypair key2;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
system.wallet (1)->insert_adhoc (key0.prv);
system.wallet (2)->insert_adhoc (key1.prv);
system.wallet (3)->insert_adhoc (key2.prv);
system.wallet (1)->store.representative_set (system.nodes[1]->wallets.tx_begin_write (), key0.pub);
system.wallet (2)->store.representative_set (system.nodes[2]->wallets.tx_begin_write (), key1.pub);
system.wallet (3)->store.representative_set (system.nodes[3]->wallets.tx_begin_write (), key2.pub);
system.wallet (0)->send_sync (nano::test_genesis_key.pub, key0.pub, level0);
system.wallet (0)->send_sync (nano::test_genesis_key.pub, key1.pub, level1);
system.wallet (0)->send_sync (nano::test_genesis_key.pub, key2.pub, level2);
// Wait for representatives
system.deadline_set (10s);
while (node.ledger.cache.rep_weights.get_rep_amounts ().size () != 4)
{
ASSERT_NO_ERROR (system.poll ());
}
node.vote_processor.calculate_weights ();
ASSERT_EQ (node.vote_processor.representatives_1.end (), node.vote_processor.representatives_1.find (key0.pub));
ASSERT_EQ (node.vote_processor.representatives_2.end (), node.vote_processor.representatives_2.find (key0.pub));
ASSERT_EQ (node.vote_processor.representatives_3.end (), node.vote_processor.representatives_3.find (key0.pub));
ASSERT_NE (node.vote_processor.representatives_1.end (), node.vote_processor.representatives_1.find (key1.pub));
ASSERT_EQ (node.vote_processor.representatives_2.end (), node.vote_processor.representatives_2.find (key1.pub));
ASSERT_EQ (node.vote_processor.representatives_3.end (), node.vote_processor.representatives_3.find (key1.pub));
ASSERT_NE (node.vote_processor.representatives_1.end (), node.vote_processor.representatives_1.find (key2.pub));
ASSERT_NE (node.vote_processor.representatives_2.end (), node.vote_processor.representatives_2.find (key2.pub));
ASSERT_EQ (node.vote_processor.representatives_3.end (), node.vote_processor.representatives_3.find (key2.pub));
ASSERT_NE (node.vote_processor.representatives_1.end (), node.vote_processor.representatives_1.find (nano::test_genesis_key.pub));
ASSERT_NE (node.vote_processor.representatives_2.end (), node.vote_processor.representatives_2.find (nano::test_genesis_key.pub));
ASSERT_NE (node.vote_processor.representatives_3.end (), node.vote_processor.representatives_3.find (nano::test_genesis_key.pub));
}
}

View file

@ -233,6 +233,18 @@ void nano::vote_processor::flush ()
}
}
size_t nano::vote_processor::size ()
{
nano::lock_guard<std::mutex> guard (mutex);
return votes.size ();
}
bool nano::vote_processor::empty ()
{
nano::lock_guard<std::mutex> guard (mutex);
return votes.empty ();
}
void nano::vote_processor::calculate_weights ()
{
nano::unique_lock<std::mutex> lock (mutex);

View file

@ -38,6 +38,8 @@ public:
nano::vote_code vote_blocking (std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>, bool = false);
void verify_votes (std::deque<std::pair<std::shared_ptr<nano::vote>, std::shared_ptr<nano::transport::channel>>> const &);
void flush ();
size_t size ();
bool empty ();
void calculate_weights ();
void stop ();
@ -67,6 +69,7 @@ private:
std::thread thread;
friend std::unique_ptr<container_info_component> collect_container_info (vote_processor & vote_processor, const std::string & name);
friend class vote_processor_weights_Test;
};
std::unique_ptr<container_info_component> collect_container_info (vote_processor & vote_processor, const std::string & name);