Adding test to show votes can be replayed to help reps who have lost track of their highest sequence number. This automatic healing avoids the need to manually re-update sequence numbers if they were ever lost, for instance when reloading a seed on a new node.

This commit is contained in:
clemahieu 2017-10-03 23:14:48 -05:00
commit ed72bd5b70
2 changed files with 56 additions and 3 deletions

View file

@ -1364,3 +1364,39 @@ TEST (node, send_callback)
}
ASSERT_EQ (std::numeric_limits <rai::uint128_t>::max () - system.nodes [0]->config.receive_minimum.number (), system.nodes [0]->balance (rai::test_genesis_key.pub));
}
// Check that votes get replayed back to nodes if they sent an old sequence number.
// This helps representatives continue from their last sequence number if their node is reinitialized and the old sequence number is lost
TEST (node, vote_replay)
{
rai::system system (24000, 2);
rai::keypair key;
auto open (std::make_shared <rai::open_block> (0, 1, key.pub, key.prv, key.pub, 0));
system.nodes [0]->generate_work (*open);
for (auto i (0); i < 11000; ++i)
{
rai::transaction transaction (system.nodes [1]->store.environment, nullptr, false);
auto vote (system.nodes [1]->store.vote_generate (transaction, rai::test_genesis_key.pub, rai::test_genesis_key.prv, open));
}
{
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, false);
std::lock_guard <std::mutex> lock (system.nodes [0]->store.vote_mutex);
auto vote (system.nodes [0]->store.vote_current (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (nullptr, vote);
}
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
auto block (system.wallet (0)->send_action (rai::test_genesis_key.pub, key.pub, rai::Gxrb_ratio));
ASSERT_NE (nullptr, block);
auto done (false);
auto iterations (0);
while (!done)
{
system.poll ();
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, false);
std::lock_guard <std::mutex> lock (system.nodes [0]->store.vote_mutex);
auto vote (system.nodes [0]->store.vote_current (transaction, rai::test_genesis_key.pub));
done = vote && (vote->sequence >= 10000);
++iterations;
ASSERT_GT (400, iterations);
}
}

View file

@ -379,13 +379,30 @@ public:
{
if (node.config.logging.network_message_logging ())
{
BOOST_LOG (node.log) << boost::str (boost::format ("Received confirm_ack message from %1% for %2%") % sender % message_a.vote->block->hash ().to_string ());
BOOST_LOG (node.log) << boost::str (boost::format ("Received confirm_ack message from %1% for %2% sequence %3%") % sender % message_a.vote->block->hash ().to_string () % std::to_string (message_a.vote->sequence));
}
++node.network.incoming.confirm_ack;
node.peers.contacted (sender, message_a.version_using);
node.peers.insert (sender, message_a.version_using);
node.process_active (message_a.vote->block);
node.vote_processor.vote (message_a.vote, sender);
auto vote (node.vote_processor.vote (message_a.vote, sender));
if (vote.code == rai::vote_code::replay)
{
assert (vote.vote->sequence > message_a.vote->sequence);
// This tries to assist rep nodes that have lost track of their highest sequence number by replaying our highest known vote back to them
// Only do this if the sequence number is significantly different to account for network reordering
// Amplify attack considerations: We're sending out a confirm_ack in response to a confirm_ack for no net traffic increase
if (vote.vote->sequence - message_a.vote->sequence > 10000)
{
rai::confirm_ack confirm (vote.vote);
std::shared_ptr <std::vector <uint8_t>> bytes (new std::vector <uint8_t>);
{
rai::vectorstream stream (*bytes);
confirm.serialize (stream);
}
node.network.confirm_send (confirm, bytes, sender);
}
}
}
void bulk_pull (rai::bulk_pull const &) override
{
@ -1573,7 +1590,7 @@ void rai::network::confirm_send (rai::confirm_ack const & confirm_a, std::shared
{
if (node.config.logging.network_publish_logging ())
{
BOOST_LOG (node.log) << boost::str (boost::format ("Sending confirm_ack for block %1% to %2%") % confirm_a.vote->block->hash ().to_string () % endpoint_a);
BOOST_LOG (node.log) << boost::str (boost::format ("Sending confirm_ack for block %1% to %2% sequence %3%") % confirm_a.vote->block->hash ().to_string () % endpoint_a % std::to_string (confirm_a.vote->sequence));
}
std::weak_ptr <rai::node> node_w (node.shared ());
++outgoing.confirm_ack;