aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
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
-rwxr-xr-xtests/functional_tests/functional_tests_rpc.py14
-rw-r--r--tests/functional_tests/make_test_signature.cc2
-rwxr-xr-xtests/functional_tests/rpc_payment.py4
-rwxr-xr-xtests/functional_tests/transfer.py52
-rwxr-xr-xtests/functional_tests/txpool.py24
-rw-r--r--tests/fuzz/http-client.cpp5
-rw-r--r--tests/unit_tests/epee_utils.cpp3
-rw-r--r--tests/unit_tests/levin.cpp1101
-rw-r--r--tests/unit_tests/net.cpp39
13 files changed, 1235 insertions, 55 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/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py
index 5f2a3d077..42d14e91a 100755
--- a/tests/functional_tests/functional_tests_rpc.py
+++ b/tests/functional_tests/functional_tests_rpc.py
@@ -34,8 +34,8 @@ try:
except:
tests = DEFAULT_TESTS
-N_MONERODS = 2
-N_WALLETS = 4
+N_MONERODS = 3
+N_WALLETS = 7
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
DIFFICULTY = 10
@@ -43,9 +43,17 @@ monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", st
monerod_extra = [
[],
["--rpc-payment-address", "44SKxxLQw929wRF6BA9paQ1EWFshNnKhXM3qz6Mo3JGDE2YG3xyzVutMStEicxbQGRfrYvAAYxH6Fe8rnD56EaNwUiqhcwR", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--data-dir", builddir + "/functional-tests-directory/monerod1"],
+ ["--rpc-restricted-bind-port", "18482", "--data-dir", builddir + "/functional-tests-directory/monerod2"]
]
-wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--daemon-port", "18180", "--log-level", "1"]
+wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1"]
wallet_extra = [
+ ["--daemon-port", "18180"],
+ ["--daemon-port", "18180"],
+ ["--daemon-port", "18180"],
+ ["--daemon-port", "18180"],
+ ["--daemon-port", "18182"],
+ ["--daemon-port", "18182"],
+ ["--daemon-port", "18182"]
]
command_lines = []
diff --git a/tests/functional_tests/make_test_signature.cc b/tests/functional_tests/make_test_signature.cc
index 6ac1a6a86..f31816841 100644
--- a/tests/functional_tests/make_test_signature.cc
+++ b/tests/functional_tests/make_test_signature.cc
@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h>
+#include "misc_language.h"
#include "string_tools.h"
#include "rpc/rpc_payment_signature.h"
@@ -69,6 +70,7 @@ int main(int argc, const char **argv)
while (count--)
{
std::string signature = cryptonote::make_rpc_payment_signature(skey);
+ epee::misc_utils::sleep_no_w(1);
printf("%s\n", signature.c_str());
}
return 0;
diff --git a/tests/functional_tests/rpc_payment.py b/tests/functional_tests/rpc_payment.py
index 3bf995f0c..5f23c2022 100755
--- a/tests/functional_tests/rpc_payment.py
+++ b/tests/functional_tests/rpc_payment.py
@@ -59,12 +59,14 @@ class RPCPaymentTest():
return fields
def refill_signatures(self):
+ self.signatures_time = time.time()
+ self.signatures = []
signatures = subprocess.check_output([self.make_test_signature, self.secret_key, '256']).decode('utf-8')
for line in signatures.split():
self.signatures.append(line.rstrip())
def get_signature(self):
- if len(self.signatures) == 0:
+ if len(self.signatures) == 0 or self.signatures_time + 10 < time.time():
self.refill_signatures()
s = self.signatures[0]
self.signatures = self.signatures[1:]
diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py
index c3d71aa9c..f7a39fa0c 100755
--- a/tests/functional_tests/transfer.py
+++ b/tests/functional_tests/transfer.py
@@ -55,7 +55,7 @@ class TransferTest():
def reset(self):
print('Resetting blockchain')
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
res = daemon.get_height()
daemon.pop_blocks(res.height - 1)
daemon.flush_txpool()
@@ -69,7 +69,7 @@ class TransferTest():
]
self.wallet = [None] * len(seeds)
for i in range(len(seeds)):
- self.wallet[i] = Wallet(idx = i)
+ self.wallet[i] = Wallet(idx = i + 4)
# close the wallet if any, will throw if none is loaded
try: self.wallet[i].close_wallet()
except: pass
@@ -77,7 +77,7 @@ class TransferTest():
def mine(self):
print("Mining some blocks")
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
res = daemon.get_info()
height = res.height
@@ -89,7 +89,7 @@ class TransferTest():
assert res.height == height + 80
def transfer(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print("Creating transfer to self")
@@ -508,7 +508,7 @@ class TransferTest():
def check_get_bulk_payments(self):
print('Checking get_bulk_payments')
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
res = daemon.get_info()
height = res.height
@@ -544,7 +544,7 @@ class TransferTest():
def check_get_payments(self):
print('Checking get_payments')
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
res = daemon.get_info()
height = res.height
@@ -587,7 +587,8 @@ class TransferTest():
assert len(res.tx_blob_list) == 1
txes[i][1] = res.tx_blob_list[0]
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
+ restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
res = daemon.send_raw_transaction(txes[0][1])
assert res.not_relayed == False
assert res.low_mixin == False
@@ -598,6 +599,18 @@ class TransferTest():
assert res.overspend == False
assert res.fee_too_low == False
+ res = restricted_daemon.send_raw_transaction(txes[0][1])
+ assert res.not_relayed == False
+ assert res.low_mixin == False
+ assert res.double_spend == False
+ assert res.invalid_input == False
+ assert res.invalid_output == False
+ assert res.too_big == False
+ assert res.overspend == False
+ assert res.fee_too_low == False
+
+ res = restricted_daemon.get_transactions([txes[0][0]])
+ assert not 'txs' in res or len(res.txs) == 0
res = daemon.get_transactions([txes[0][0]])
assert len(res.txs) >= 1
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
@@ -615,6 +628,19 @@ class TransferTest():
assert res.fee_too_low == False
assert res.too_few_outputs == False
+ res = restricted_daemon.send_raw_transaction(txes[1][1])
+ assert res.not_relayed == False
+ assert res.low_mixin == False
+ assert res.double_spend == True
+ assert res.invalid_input == False
+ assert res.invalid_output == False
+ assert res.too_big == False
+ assert res.overspend == False
+ assert res.fee_too_low == False
+ assert res.too_few_outputs == False
+
+ res = restricted_daemon.get_transactions([txes[0][0]])
+ assert not 'txs' in res or len(res.txs) == 0
res = daemon.get_transactions([txes[0][0]])
assert len(res.txs) >= 1
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
@@ -623,13 +649,13 @@ class TransferTest():
def sweep_dust(self):
print("Sweeping dust")
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
self.wallet[0].refresh()
res = self.wallet[0].sweep_dust()
assert not 'tx_hash_list' in res or len(res.tx_hash_list) == 0 # there's just one, but it cannot meet the fee
def sweep_single(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print("Sending single output")
@@ -685,7 +711,7 @@ class TransferTest():
assert len([t for t in res.transfers if t.key_image == ki]) == 1
def check_destinations(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print("Checking transaction destinations")
@@ -741,7 +767,7 @@ class TransferTest():
self.wallet[0].refresh()
def check_tx_notes(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print('Testing tx notes')
res = self.wallet[0].get_transfers()
@@ -758,7 +784,7 @@ class TransferTest():
assert res.notes == ['out txid', 'in txid']
def check_rescan(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print('Testing rescan_spent')
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
@@ -798,7 +824,7 @@ class TransferTest():
assert sorted(old_t_out, key = lambda k: k['txid']) == sorted(new_t_out, key = lambda k: k['txid'])
def check_is_key_image_spent(self):
- daemon = Daemon()
+ daemon = Daemon(idx = 2)
print('Testing is_key_image_spent')
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
diff --git a/tests/functional_tests/txpool.py b/tests/functional_tests/txpool.py
index 27ae89764..2d7f69f3c 100755
--- a/tests/functional_tests/txpool.py
+++ b/tests/functional_tests/txpool.py
@@ -45,14 +45,14 @@ class TransferTest():
def reset(self):
print('Resetting blockchain')
- daemon = Daemon()
+ daemon = Daemon(idx=2)
res = daemon.get_height()
daemon.pop_blocks(res.height - 1)
daemon.flush_txpool()
def create(self):
print('Creating wallet')
- wallet = Wallet()
+ wallet = Wallet(idx = 4)
# close the wallet if any, will throw if none is loaded
try: wallet.close_wallet()
except: pass
@@ -61,8 +61,8 @@ class TransferTest():
def mine(self):
print("Mining some blocks")
- daemon = Daemon()
- wallet = Wallet()
+ daemon = Daemon(idx = 2)
+ wallet = Wallet(idx = 4)
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 80)
wallet.refresh()
@@ -70,8 +70,8 @@ class TransferTest():
def create_txes(self, address, ntxes):
print('Creating ' + str(ntxes) + ' transactions')
- daemon = Daemon()
- wallet = Wallet()
+ daemon = Daemon(idx = 2)
+ wallet = Wallet(idx = 4)
dst = {'address': address, 'amount': 1000000000000}
@@ -83,8 +83,10 @@ class TransferTest():
return txes
def check_empty_pool(self):
- daemon = Daemon()
+ self.check_empty_rpc_pool(Daemon(idx = 2))
+ self.check_empty_rpc_pool(Daemon(idx = 2, restricted_rpc = True))
+ def check_empty_rpc_pool(self, daemon):
res = daemon.get_transaction_pool_hashes()
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
res = daemon.get_transaction_pool_stats()
@@ -103,8 +105,9 @@ class TransferTest():
assert res.pool_stats.num_double_spends == 0
def check_txpool(self):
- daemon = Daemon()
- wallet = Wallet()
+ daemon = Daemon(idx = 2)
+ restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
+ wallet = Wallet(idx = 4)
res = daemon.get_info()
height = res.height
@@ -117,6 +120,7 @@ class TransferTest():
res = daemon.get_info()
assert res.tx_pool_size == txpool_size + 5
txpool_size = res.tx_pool_size
+ self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size
@@ -160,6 +164,7 @@ class TransferTest():
print('Flushing 2 transactions')
txes_keys = list(txes.keys())
daemon.flush_txpool([txes_keys[1], txes_keys[3]])
+ self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size - 2
assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0
@@ -210,6 +215,7 @@ class TransferTest():
print('Flushing unknown transactions')
unknown_txids = ['1'*64, '2'*64, '3'*64]
daemon.flush_txpool(unknown_txids)
+ self.check_empty_rpc_pool(restricted_daemon)
res = daemon.get_transaction_pool()
assert len(res.transactions) == txpool_size - 2
diff --git a/tests/fuzz/http-client.cpp b/tests/fuzz/http-client.cpp
index 1750838ae..ea6d5a2ad 100644
--- a/tests/fuzz/http-client.cpp
+++ b/tests/fuzz/http-client.cpp
@@ -29,6 +29,7 @@
#include "include_base_utils.h"
#include "file_io_utils.h"
#include "net/http_client.h"
+#include "net/net_ssl.h"
#include "fuzzer.h"
class dummy_client
@@ -46,6 +47,10 @@ public:
data.clear();
return true;
}
+ void set_ssl(epee::net_utils::ssl_options_t ssl_options) { }
+ bool is_connected(bool *ssl = NULL) { return true; }
+ uint64_t get_bytes_sent() const { return 1; }
+ uint64_t get_bytes_received() const { return 1; }
void set_test_data(const std::string &s) { data = s; }
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 42bbb26bb..4f42140b3 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -841,6 +841,9 @@ TEST(HexLocale, String)
// decoding it this way also, ignoring spaces and colons between the numbers
hex.assign("00:ff 0f:f0");
EXPECT_EQ(source, epee::from_hex_locale::to_vector(hex));
+
+ hex.append("f0");
+ EXPECT_EQ(source, epee::from_hex_locale::to_vector(boost::string_ref{hex.data(), hex.size() - 2}));
}
TEST(ToHex, Array)
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);
}
}
}
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index 36cb28ae0..f5aef4796 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -1702,6 +1702,45 @@ TEST(zmq, read_write)
EXPECT_EQ(message, *received);
}
+TEST(zmq, read_write_slice)
+{
+ net::zmq::context context{zmq_init(1)};
+ ASSERT_NE(nullptr, context);
+
+ net::zmq::socket send_socket{zmq_socket(context.get(), ZMQ_REQ)};
+ net::zmq::socket recv_socket{zmq_socket(context.get(), ZMQ_REP)};
+ ASSERT_NE(nullptr, send_socket);
+ ASSERT_NE(nullptr, recv_socket);
+
+ ASSERT_EQ(0u, zmq_bind(recv_socket.get(), "inproc://testing"));
+ ASSERT_EQ(0u, zmq_connect(send_socket.get(), "inproc://testing"));
+
+ std::string message;
+ message.resize(1024);
+ crypto::rand(message.size(), reinterpret_cast<std::uint8_t*>(std::addressof(message[0])));
+
+ {
+ epee::byte_slice slice_message{{epee::strspan<std::uint8_t>(message)}};
+ ASSERT_TRUE(bool(net::zmq::send(std::move(slice_message), send_socket.get())));
+ EXPECT_TRUE(slice_message.empty());
+ }
+
+ const expect<std::string> received = net::zmq::receive(recv_socket.get());
+ ASSERT_TRUE(bool(received));
+ EXPECT_EQ(message, *received);
+}
+
+TEST(zmq, write_slice_fail)
+{
+ std::string message;
+ message.resize(1024);
+ crypto::rand(message.size(), reinterpret_cast<std::uint8_t*>(std::addressof(message[0])));
+
+ epee::byte_slice slice_message{std::move(message)};
+ EXPECT_FALSE(bool(net::zmq::send(std::move(slice_message), nullptr)));
+ EXPECT_TRUE(slice_message.empty());
+}
+
TEST(zmq, read_write_multipart)
{
net::zmq::context context{zmq_init(1)};