Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pwojcikdev committed Mar 3, 2025
1 parent ef63c23 commit e992597
Showing 1 changed file with 204 additions and 2 deletions.
206 changes: 204 additions & 2 deletions nano/core_test/online_reps.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "nano/node/election.hpp"

#include <nano/node/online_reps.hpp>
#include <nano/node/transport/fake.hpp>
#include <nano/secure/vote.hpp>
Expand All @@ -8,8 +10,8 @@

TEST (online_reps, basic)
{
nano::test::system system (1);
auto & node1 (*system.nodes[0]);
nano::test::system system;
auto & node1 = *system.add_node ();
// 1 sample of minimum weight
ASSERT_EQ (node1.config.online_weight_minimum, node1.online_reps.trended ());
auto vote (std::make_shared<nano::vote> ());
Expand Down Expand Up @@ -69,4 +71,204 @@ TEST (online_reps, election)
ASSERT_EQ (0, node1.online_reps.online ());
node1.vote_processor.vote_blocking (vote, std::make_shared<nano::transport::fake::channel> (node1));
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, node1.online_reps.online ());
}

// Online reps should be able to observe remote representative
TEST (online_reps, observe)
{
nano::test::system system;
auto & node = *system.add_node ();
ASSERT_EQ (0, node.online_reps.online ());

// Addd genesis representative
auto & node_rep = *system.add_node ();
system.wallet (1)->insert_adhoc (nano::dev::genesis_key.prv);

// The node should see that weight as online
ASSERT_TIMELY_EQ (10s, node.online_reps.online (), nano::dev::constants.genesis_amount);
ASSERT_ALWAYS_EQ (1s, node.online_reps.online (), nano::dev::constants.genesis_amount);
}

TEST (online_reps, observe_multiple)
{
nano::test::system system;
auto & node = *system.add_node ();
ASSERT_EQ (0, node.online_reps.online ());

auto & node_rep1 = *system.add_node (); // key1
auto & node_rep2 = *system.add_node (); // key2 & key3

auto const weight_1 = nano::nano_ratio * 1000;
auto const weight_2 = nano::nano_ratio * 1000000;
auto const weight_3 = nano::nano_ratio * 10000000;

nano::keypair key1, key2, key3;

// Distribute genesis voting weight
{
nano::block_builder builder;
auto send1 = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight_1)
.link (key1.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
auto send2 = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (send1->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight_1 - weight_2)
.link (key2.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build ();
auto send3 = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (send2->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight_1 - weight_2 - weight_3)
.link (key3.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (send2->hash ()))
.build ();
auto open1 = builder.state ()
.account (key1.pub)
.previous (0)
.representative (key1.pub)
.balance (weight_1)
.link (send1->hash ())
.sign (key1.prv, key1.pub)
.work (*system.work.generate (key1.pub))
.build ();
auto open2 = builder.state ()
.account (key2.pub)
.previous (0)
.representative (key2.pub)
.balance (weight_2)
.link (send2->hash ())
.sign (key2.prv, key2.pub)
.work (*system.work.generate (key2.pub))
.build ();
auto open3 = builder.state ()
.account (key3.pub)
.previous (0)
.representative (key3.pub)
.balance (weight_3)
.link (send3->hash ())
.sign (key3.prv, key3.pub)
.work (*system.work.generate (key3.pub))
.build ();
ASSERT_TRUE (nano::test::process (node_rep1, { send1, send2, send3, open1, open2, open3 }));
ASSERT_TRUE (nano::test::process (node_rep2, { send1, send2, send3, open1, open2, open3 }));
}

// Add rep keys to nodes
system.wallet (1)->insert_adhoc (key1.prv);
system.wallet (2)->insert_adhoc (key2.prv);
system.wallet (2)->insert_adhoc (key3.prv);

ASSERT_TIMELY_EQ (10s, node.online_reps.online (), weight_1 + weight_2 + weight_3);
ASSERT_ALWAYS_EQ (1s, node.online_reps.online (), weight_1 + weight_2 + weight_3);
}

// Online weight calculation should include local representative
TEST (online_reps, observe_local)
{
nano::test::system system;
auto & node = *system.add_node ();
ASSERT_EQ (0, node.online_reps.online ());
system.wallet (0)->insert_adhoc (nano::dev::genesis_key.prv);
ASSERT_TIMELY_EQ (10s, node.online_reps.online (), nano::dev::constants.genesis_amount);
ASSERT_ALWAYS_EQ (1s, node.online_reps.online (), nano::dev::constants.genesis_amount);
}

// Online weight calculation should include slower but active representatives
TEST (online_reps, observe_slow)
{
nano::test::system system;
auto & node = *system.add_node ();
ASSERT_EQ (0, node.online_reps.online ());

// Enough to reach quorum by a single vote
auto const weight = nano::nano_ratio * 80000000;

nano::keypair key1, key2; // Fast and slow reps

// Distribute genesis voting weight
nano::block_builder builder;
auto send1 = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (nano::dev::genesis->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight)
.link (key1.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (nano::dev::genesis->hash ()))
.build ();
auto send2 = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (send1->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight * 2)
.link (key2.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (send1->hash ()))
.build ();
auto open1 = builder.state ()
.account (key1.pub)
.previous (0)
.representative (key1.pub)
.balance (weight)
.link (send1->hash ())
.sign (key1.prv, key1.pub)
.work (*system.work.generate (key1.pub))
.build ();
auto open2 = builder.state ()
.account (key2.pub)
.previous (0)
.representative (key2.pub)
.balance (weight)
.link (send2->hash ())
.sign (key2.prv, key2.pub)
.work (*system.work.generate (key2.pub))
.build ();
ASSERT_TRUE (nano::test::process (node, { send1, send2, open1, open2 }));
nano::test::confirm (node, { send1, send2, open1, open2 });

ASSERT_EQ (node.active.size (), 0);

// Add a block that we can vote on
auto send_dummy = builder.state ()
.account (nano::dev::genesis_key.pub)
.previous (send2->hash ())
.representative (nano::dev::genesis_key.pub)
.balance (nano::dev::constants.genesis_amount - weight * 2 - nano::nano_ratio)
.link (nano::keypair{}.pub)
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
.work (*system.work.generate (send2->hash ()))
.build ();
ASSERT_TRUE (nano::test::process (node, { send_dummy }));

// Wait for election for the block to be activated
std::shared_ptr<nano::election> election;
ASSERT_TIMELY (5s, election = node.active.election (send_dummy->qualified_root ()));
ASSERT_TRUE (election->contains (send_dummy->hash ()));

// Issue vote from a fast rep
auto vote_fast = nano::test::make_final_vote (key1, { send_dummy });
node.vote_processor.vote_blocking (vote_fast, nano::test::fake_channel (node));

ASSERT_TIMELY (5s, election->confirmed ());
ASSERT_TIMELY (5s, !node.active.active (send_dummy->qualified_root ())); // No longer present in AEC
ASSERT_TIMELY_EQ (5s, node.online_reps.online (), weight);

// Issue vote from a slow rep
auto vote_slow = nano::test::make_final_vote (key2, { send_dummy });
node.vote_processor.vote_blocking (vote_slow, nano::test::fake_channel (node));

// The slow rep weight should still be counted as online, even though it arrived slightly after the election already reached quorum
ASSERT_TIMELY_EQ (5s, node.online_reps.online (), weight * 2);
}

0 comments on commit e992597

Please sign in to comment.