aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLee Clagett <code@leeclagett.com>2019-11-13 14:12:32 +0000
committerLee Clagett <code@leeclagett.com>2020-03-26 15:01:30 +0000
commit02d887c2e58bd8e66ef8823e59669439d448bfec (patch)
tree0c5ff6825f6555f8930589fa118fe263d29a018b /tests
parentMerge pull request #6405 (diff)
downloadmonero-02d887c2e58bd8e66ef8823e59669439d448bfec.tar.xz
Adding Dandelion++ support to public networks:
- New flag in NOTIFY_NEW_TRANSACTION to indicate stem mode - Stem loops detected in tx_pool.cpp - Embargo timeout for a blackhole attack during stem phase
Diffstat (limited to 'tests')
-rw-r--r--tests/core_tests/chaingen.h7
-rw-r--r--tests/core_tests/chaingen_main.cpp1
-rw-r--r--tests/core_tests/tx_pool.cpp29
-rw-r--r--tests/core_tests/tx_pool.h9
-rw-r--r--tests/unit_tests/levin.cpp1101
5 files changed, 1118 insertions, 29 deletions
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 80ce7404b..453ee923d 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -116,7 +116,8 @@ struct event_visitor_settings
{
set_txs_keeped_by_block = 1 << 0,
set_txs_do_not_relay = 1 << 1,
- set_local_relay = 1 << 2
+ set_local_relay = 1 << 2,
+ set_txs_stem = 1 << 3
};
event_visitor_settings(int a_mask = 0)
@@ -548,6 +549,10 @@ public:
{
m_tx_relay = cryptonote::relay_method::none;
}
+ else if (settings.mask & event_visitor_settings::set_txs_stem)
+ {
+ m_tx_relay = cryptonote::relay_method::stem;
+ }
else
{
m_tx_relay = cryptonote::relay_method::fluff;
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index 014c7475b..8a313140c 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -162,6 +162,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(txpool_double_spend_norelay);
GENERATE_AND_PLAY(txpool_double_spend_local);
GENERATE_AND_PLAY(txpool_double_spend_keyimage);
+ GENERATE_AND_PLAY(txpool_stem_loop);
// Double spend
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);
diff --git a/tests/core_tests/tx_pool.cpp b/tests/core_tests/tx_pool.cpp
index cc738c4ba..b60dd00fc 100644
--- a/tests/core_tests/tx_pool.cpp
+++ b/tests/core_tests/tx_pool.cpp
@@ -552,7 +552,6 @@ bool txpool_double_spend_local::generate(std::vector<test_event_entry>& events)
DO_CALLBACK(events, "mark_no_new");
events.push_back(tx_0);
DO_CALLBACK(events, "check_txpool_spent_keys");
- DO_CALLBACK(events, "mark_timestamp_change");
DO_CALLBACK(events, "check_unchanged");
SET_EVENT_VISITOR_SETT(events, 0);
DO_CALLBACK(events, "timestamp_change_pause");
@@ -580,6 +579,7 @@ bool txpool_double_spend_keyimage::generate(std::vector<test_event_entry>& event
const std::size_t tx_index1 = events.size();
MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+ SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_stem);
DO_CALLBACK(events, "increase_all_tx_count");
DO_CALLBACK(events, "check_txpool_spent_keys");
DO_CALLBACK(events, "mark_timestamp_change");
@@ -611,3 +611,30 @@ bool txpool_double_spend_keyimage::generate(std::vector<test_event_entry>& event
return true;
}
+bool txpool_stem_loop::generate(std::vector<test_event_entry>& events) const
+{
+ INIT_MEMPOOL_TEST();
+
+ DO_CALLBACK(events, "check_txpool_spent_keys");
+ SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_stem);
+ DO_CALLBACK(events, "mark_no_new");
+
+ MAKE_TX(events, tx_0, miner_account, bob_account, send_amount, blk_0);
+
+ DO_CALLBACK(events, "increase_all_tx_count");
+ DO_CALLBACK(events, "check_txpool_spent_keys");
+ DO_CALLBACK(events, "mark_timestamp_change");
+ DO_CALLBACK(events, "check_new_hidden");
+ DO_CALLBACK(events, "timestamp_change_pause");
+ events.push_back(tx_0);
+ DO_CALLBACK(events, "increase_broadcasted_tx_count");
+ DO_CALLBACK(events, "check_txpool_spent_keys");
+ DO_CALLBACK(events, "mark_timestamp_change");
+ DO_CALLBACK(events, "check_new_broadcasted");
+ DO_CALLBACK(events, "timestamp_change_pause");
+ DO_CALLBACK(events, "mark_no_new");
+ events.push_back(tx_0);
+ DO_CALLBACK(events, "check_unchanged");
+
+ return true;
+}
diff --git a/tests/core_tests/tx_pool.h b/tests/core_tests/tx_pool.h
index eb71dcf79..8a27e98f0 100644
--- a/tests/core_tests/tx_pool.h
+++ b/tests/core_tests/tx_pool.h
@@ -127,3 +127,12 @@ struct txpool_double_spend_keyimage : txpool_double_spend_base
bool generate(std::vector<test_event_entry>& events) const;
};
+
+struct txpool_stem_loop : txpool_double_spend_base
+{
+ txpool_stem_loop()
+ : txpool_double_spend_base()
+ {}
+
+ bool generate(std::vector<test_event_entry>& events) const;
+};
diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp
index 720103e5a..62b101a42 100644
--- a/tests/unit_tests/levin.cpp
+++ b/tests/unit_tests/levin.cpp
@@ -34,11 +34,14 @@
#include <gtest/gtest.h>
#include <limits>
#include <set>
+#include <map>
#include "byte_slice.h"
#include "crypto/crypto.h"
#include "cryptonote_basic/connection_context.h"
+#include "cryptonote_config.h"
#include "cryptonote_core/cryptonote_core.h"
+#include "cryptonote_core/i_core_events.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "cryptonote_protocol/levin_notify.h"
#include "int-util.h"
@@ -113,6 +116,44 @@ namespace
std::deque<epee::byte_slice> send_queue_;
};
+ class test_core_events final : public cryptonote::i_core_events
+ {
+ std::map<cryptonote::relay_method, std::vector<cryptonote::blobdata>> relayed_;
+
+ virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> txes, cryptonote::relay_method relay) override final
+ {
+ std::vector<cryptonote::blobdata>& cached = relayed_[relay];
+ for (const auto& tx : txes)
+ cached.push_back(tx);
+ }
+
+ public:
+ test_core_events()
+ : relayed_()
+ {}
+
+ std::size_t relayed_method_size() const noexcept
+ {
+ return relayed_.size();
+ }
+
+ bool has_stem_txes() const noexcept
+ {
+ return relayed_.count(cryptonote::relay_method::stem);
+ }
+
+ std::vector<cryptonote::blobdata> take_relayed(cryptonote::relay_method relay)
+ {
+ auto elems = relayed_.find(relay);
+ if (elems == relayed_.end())
+ throw std::logic_error{"on_transactions_relayed empty"};
+
+ std::vector<cryptonote::blobdata> out{std::move(elems->second)};
+ relayed_.erase(elems);
+ return out;
+ }
+ };
+
class test_connection
{
test_endpoint endpoint_;
@@ -146,6 +187,11 @@ namespace
{
return context_.m_connection_id;
}
+
+ bool is_incoming() const noexcept
+ {
+ return context_.m_is_income;
+ }
};
struct received_message
@@ -155,7 +201,7 @@ namespace
std::string payload;
};
- class test_receiver : public epee::levin::levin_commands_handler<cryptonote::levin::detail::p2p_context>
+ class test_receiver final : public epee::levin::levin_commands_handler<cryptonote::levin::detail::p2p_context>
{
std::deque<received_message> invoked_;
std::deque<received_message> notified_;
@@ -253,7 +299,8 @@ namespace
random_generator_(),
io_service_(),
receiver_(),
- contexts_()
+ contexts_(),
+ events_()
{
connections_->set_handler(std::addressof(receiver_), nullptr);
}
@@ -262,6 +309,7 @@ namespace
{
EXPECT_EQ(0u, receiver_.invoked_size());
EXPECT_EQ(0u, receiver_.notified_size());
+ EXPECT_EQ(0u, events_.relayed_method_size());
}
void add_connection(const bool is_incoming)
@@ -283,6 +331,7 @@ namespace
boost::asio::io_service io_service_;
test_receiver receiver_;
std::deque<test_connection> contexts_;
+ test_core_events events_;
};
}
@@ -434,11 +483,11 @@ TEST_F(levin_notify, defaulted)
EXPECT_FALSE(status.has_noise);
EXPECT_FALSE(status.connections_filled);
}
- EXPECT_TRUE(notifier.send_txs({}, random_generator_()));
+ EXPECT_TRUE(notifier.send_txs({}, random_generator_(), events_, cryptonote::relay_method::local));
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'e');
- EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_()));
+ EXPECT_FALSE(notifier.send_txs(std::move(txs), random_generator_(), events_, cryptonote::relay_method::local));
}
TEST_F(levin_notify, fluff_without_padding)
@@ -455,11 +504,6 @@ TEST_F(levin_notify, fluff_without_padding)
}
notifier.new_out_connection();
io_service_.poll();
- {
- const auto status = notifier.get_status();
- EXPECT_FALSE(status.has_noise);
- EXPECT_FALSE(status.connections_filled); // not tracked
- }
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
@@ -468,7 +512,7 @@ TEST_F(levin_notify, fluff_without_padding)
ASSERT_EQ(10u, contexts_.size());
{
auto context = contexts_.begin();
- EXPECT_TRUE(notifier.send_txs(txs, context->get_id()));
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
@@ -479,6 +523,7 @@ TEST_F(levin_notify, fluff_without_padding)
for (++context; context != contexts_.end(); ++context)
EXPECT_EQ(1u, context->process_send_queue());
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
std::sort(txs.begin(), txs.end());
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9; ++count)
@@ -486,13 +531,14 @@ TEST_F(levin_notify, fluff_without_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
-TEST_F(levin_notify, fluff_with_padding)
+TEST_F(levin_notify, stem_without_padding)
{
- cryptonote::levin::notify notifier = make_notifier(0, true, true);
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
for (unsigned count = 0; count < 10; ++count)
add_connection(count % 2 == 0);
@@ -504,41 +550,428 @@ TEST_F(levin_notify, fluff_with_padding)
}
notifier.new_out_connection();
io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'f');
+ txs[1].resize(200, 'e');
+
+ std::vector<cryptonote::blobdata> sorted_txs = txs;
+ std::sort(sorted_txs.begin(), sorted_txs.end());
+
+ ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ if (is_stem)
+ EXPECT_EQ(txs, notification.txs);
+ else
+ EXPECT_EQ(sorted_txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
+TEST_F(levin_notify, local_without_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
- EXPECT_FALSE(status.connections_filled); // not tracked
+ EXPECT_FALSE(status.connections_filled);
}
+ notifier.new_out_connection();
+ io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
+ std::vector<cryptonote::blobdata> sorted_txs = txs;
+ std::sort(sorted_txs.begin(), sorted_txs.end());
+
ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
{
auto context = contexts_.begin();
- EXPECT_TRUE(notifier.send_txs(txs, context->get_id()));
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ if (is_stem)
+ EXPECT_EQ(txs, notification.txs);
+ else
+ EXPECT_EQ(sorted_txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
+TEST_F(levin_notify, block_without_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, none_without_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, fluff_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'f');
+ txs[1].resize(200, 'e');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ std::sort(txs.begin(), txs.end());
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
EXPECT_EQ(1u, context->process_send_queue());
- std::sort(txs.begin(), txs.end());
ASSERT_EQ(9u, receiver_.notified_size());
for (unsigned count = 0; count < 9; ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_FALSE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
+TEST_F(levin_notify, stem_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
+TEST_F(levin_notify, local_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ bool has_stemmed = false;
+ bool has_fluffed = false;
+ while (!has_stemmed || !has_fluffed)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ const bool is_stem = events_.has_stem_txes();
+ EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
+
+ if (!is_stem)
+ {
+ notifier.run_fluff();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent && is_stem)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(is_stem ? 1u : 9u, send_count);
+ ASSERT_EQ(is_stem ? 1u : 9u, receiver_.notified_size());
+ for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
+ }
+
+ has_stemmed |= is_stem;
+ has_fluffed |= !is_stem;
+ notifier.run_epoch();
+ }
+}
+
+TEST_F(levin_notify, block_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, none_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, true, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
TEST_F(levin_notify, private_fluff_without_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, false, false);
@@ -553,20 +986,66 @@ TEST_F(levin_notify, private_fluff_without_padding)
}
notifier.new_out_connection();
io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_stem_without_padding)
+{
+ // private mode always uses fluff but marked as stem
+ cryptonote::levin::notify notifier = make_notifier(0, false, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
- EXPECT_FALSE(status.connections_filled); // not tracked
+ EXPECT_FALSE(status.connections_filled);
}
+ notifier.new_out_connection();
+ io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
- txs[0].resize(100, 'f');
- txs[1].resize(200, 'e');
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
ASSERT_EQ(10u, contexts_.size());
{
auto context = contexts_.begin();
- EXPECT_TRUE(notifier.send_txs(txs, context->get_id()));
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
@@ -574,7 +1053,8 @@ TEST_F(levin_notify, private_fluff_without_padding)
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
- std::sort(txs.begin(), txs.end());
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
@@ -588,10 +1068,122 @@ TEST_F(levin_notify, private_fluff_without_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
}
}
}
+TEST_F(levin_notify, private_local_without_padding)
+{
+ // private mode always uses fluff but marked as stem
+ cryptonote::levin::notify notifier = make_notifier(0, false, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::local));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_block_without_padding)
+{
+ // private mode always uses fluff but marked as stem
+ cryptonote::levin::notify notifier = make_notifier(0, false, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, private_none_without_padding)
+{
+ // private mode always uses fluff but marked as stem
+ cryptonote::levin::notify notifier = make_notifier(0, false, false);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
TEST_F(levin_notify, private_fluff_with_padding)
{
cryptonote::levin::notify notifier = make_notifier(0, false, true);
@@ -606,20 +1198,65 @@ TEST_F(levin_notify, private_fluff_with_padding)
}
notifier.new_out_connection();
io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::fluff));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_stem_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, false, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
{
const auto status = notifier.get_status();
EXPECT_FALSE(status.has_noise);
- EXPECT_FALSE(status.connections_filled); // not tracked
+ EXPECT_FALSE(status.connections_filled);
}
+ notifier.new_out_connection();
+ io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
- txs[0].resize(100, 'f');
- txs[1].resize(200, 'e');
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
ASSERT_EQ(10u, contexts_.size());
{
auto context = contexts_.begin();
- EXPECT_TRUE(notifier.send_txs(txs, context->get_id()));
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
@@ -627,7 +1264,58 @@ TEST_F(levin_notify, private_fluff_with_padding)
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
- std::sort(txs.begin(), txs.end());
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const bool is_incoming = ((context - contexts_.begin()) % 2 == 0);
+ EXPECT_EQ(is_incoming ? 0u : 1u, context->process_send_queue());
+ }
+
+ ASSERT_EQ(5u, receiver_.notified_size());
+ for (unsigned count = 0; count < 5; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_FALSE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_local_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, false, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::local));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::local));
+
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
@@ -641,6 +1329,301 @@ TEST_F(levin_notify, private_fluff_with_padding)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_FALSE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, private_block_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, false, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::block));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, private_none_with_padding)
+{
+ cryptonote::levin::notify notifier = make_notifier(0, false, true);
+
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(10u, contexts_.size());
+ {
+ auto context = contexts_.begin();
+ EXPECT_FALSE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::none));
+
+ io_service_.reset();
+ ASSERT_EQ(0u, io_service_.poll());
+ }
+}
+
+TEST_F(levin_notify, stem_mappings)
+{
+ static constexpr const unsigned test_connections_count = (CRYPTONOTE_DANDELIONPP_STEMS + 1) * 2;
+
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < test_connections_count; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(test_connections_count, contexts_.size());
+ for (;;)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ if (events_.has_stem_txes())
+ break;
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ EXPECT_EQ(1u, context->process_send_queue());
+
+ ASSERT_EQ(test_connections_count - 1, receiver_.notified_size());
+ for (unsigned count = 0; count < test_connections_count - 1; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
+ }
+
+ notifier.run_epoch();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
+
+ std::set<boost::uuids::uuid> used;
+ std::map<boost::uuids::uuid, boost::uuids::uuid> mappings;
+ {
+ std::size_t send_count = 0;
+ for (auto context = contexts_.begin(); context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ used.insert(context->get_id());
+ mappings[contexts_.front().get_id()] = context->get_id();
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(1u, send_count);
+ ASSERT_EQ(1u, receiver_.notified_size());
+ for (unsigned count = 0; count < 1u; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+
+ for (unsigned i = 0; i < contexts_.size() * 2; i += 2)
+ {
+ auto& incoming = contexts_[i % contexts_.size()];
+ EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
+
+ std::size_t send_count = 0;
+ for (auto context = contexts_.begin(); context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ used.insert(context->get_id());
+
+ auto inserted = mappings.emplace(incoming.get_id(), context->get_id()).first;
+ EXPECT_EQ(inserted->second, context->get_id()) << "incoming index " << i;
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(1u, send_count);
+ ASSERT_EQ(1u, receiver_.notified_size());
+ for (unsigned count = 0; count < 1u; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+
+ EXPECT_EQ(CRYPTONOTE_DANDELIONPP_STEMS, used.size());
+}
+
+TEST_F(levin_notify, fluff_multiple)
+{
+ static constexpr const unsigned test_connections_count = (CRYPTONOTE_DANDELIONPP_STEMS + 1) * 2;
+
+ cryptonote::levin::notify notifier = make_notifier(0, true, false);
+
+ for (unsigned count = 0; count < test_connections_count; ++count)
+ add_connection(count % 2 == 0);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_FALSE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ notifier.new_out_connection();
+ io_service_.poll();
+
+ std::vector<cryptonote::blobdata> txs(2);
+ txs[0].resize(100, 'e');
+ txs[1].resize(200, 'f');
+
+ ASSERT_EQ(test_connections_count, contexts_.size());
+ for (;;)
+ {
+ auto context = contexts_.begin();
+ EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ if (!events_.has_stem_txes())
+ break;
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
+
+ std::size_t send_count = 0;
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ {
+ const std::size_t sent = context->process_send_queue();
+ if (sent)
+ {
+ EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
+ EXPECT_FALSE(context->is_incoming());
+ }
+ send_count += sent;
+ }
+
+ EXPECT_EQ(1u, send_count);
+ ASSERT_EQ(1u, receiver_.notified_size());
+ for (unsigned count = 0; count < 1; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+
+ notifier.run_epoch();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ }
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ {
+ auto context = contexts_.begin();
+ EXPECT_EQ(0u, context->process_send_queue());
+ for (++context; context != contexts_.end(); ++context)
+ EXPECT_EQ(1u, context->process_send_queue());
+
+ ASSERT_EQ(contexts_.size() - 1, receiver_.notified_size());
+ for (unsigned count = 0; count < contexts_.size() - 1; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
+ }
+ }
+
+ for (unsigned i = 0; i < contexts_.size() * 2; i += 2)
+ {
+ auto& incoming = contexts_[i % contexts_.size()];
+ EXPECT_TRUE(notifier.send_txs(txs, incoming.get_id(), events_, cryptonote::relay_method::stem));
+
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ notifier.run_fluff();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+
+ for (auto& context : contexts_)
+ {
+ if (std::addressof(incoming) == std::addressof(context))
+ EXPECT_EQ(0u, context.process_send_queue());
+ else
+ EXPECT_EQ(1u, context.process_send_queue());
+ }
+
+ ASSERT_EQ(contexts_.size() - 1, receiver_.notified_size());
+ for (unsigned count = 0; count < contexts_.size() - 1; ++count)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_TRUE(notification.dandelionpp_fluff);
}
}
}
@@ -680,10 +1663,12 @@ TEST_F(levin_notify, noise)
EXPECT_EQ(0u, receiver_.notified_size());
}
- EXPECT_TRUE(notifier.send_txs(txs, incoming_id));
+ EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::local));
notifier.run_stems();
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::local));
{
std::size_t sent = 0;
for (auto& context : contexts_)
@@ -695,11 +1680,68 @@ TEST_F(levin_notify, noise)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
}
}
txs[0].resize(3000, 'r');
- EXPECT_TRUE(notifier.send_txs(txs, incoming_id));
+ EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::fluff));
+ notifier.run_stems();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
+ {
+ std::size_t sent = 0;
+ for (auto& context : contexts_)
+ sent += context.process_send_queue();
+
+ EXPECT_EQ(2u, sent);
+ EXPECT_EQ(0u, receiver_.notified_size());
+ }
+
+ notifier.run_stems();
+ io_service_.reset();
+ ASSERT_LT(0u, io_service_.poll());
+ {
+ std::size_t sent = 0;
+ for (auto& context : contexts_)
+ sent += context.process_send_queue();
+
+ ASSERT_EQ(2u, sent);
+ while (sent--)
+ {
+ auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
+ EXPECT_EQ(txs, notification.txs);
+ EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
+ }
+ }
+}
+
+TEST_F(levin_notify, noise_stem)
+{
+ for (unsigned count = 0; count < 10; ++count)
+ add_connection(count % 2 == 0);
+
+ std::vector<cryptonote::blobdata> txs(1);
+ txs[0].resize(1900, 'h');
+
+ const boost::uuids::uuid incoming_id = random_generator_();
+ cryptonote::levin::notify notifier = make_notifier(2048, false, true);
+
+ {
+ const auto status = notifier.get_status();
+ EXPECT_TRUE(status.has_noise);
+ EXPECT_FALSE(status.connections_filled);
+ }
+ ASSERT_LT(0u, io_service_.poll());
+ {
+ const auto status = notifier.get_status();
+ EXPECT_TRUE(status.has_noise);
+ EXPECT_TRUE(status.connections_filled);
+ }
+
notifier.run_stems();
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
@@ -712,9 +1754,13 @@ TEST_F(levin_notify, noise)
EXPECT_EQ(0u, receiver_.notified_size());
}
+ EXPECT_TRUE(notifier.send_txs(txs, incoming_id, events_, cryptonote::relay_method::stem));
notifier.run_stems();
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
+
+ // downgraded to local when being notified
+ EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::local));
{
std::size_t sent = 0;
for (auto& context : contexts_)
@@ -726,6 +1772,7 @@ TEST_F(levin_notify, noise)
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_TRUE(notification._.empty());
+ EXPECT_FALSE(notification.dandelionpp_fluff);
}
}
}