aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/README.md5
-rw-r--r--tests/core_tests/transaction_tests.cpp2
-rw-r--r--tests/core_tests/tx_pool.cpp7
-rw-r--r--tests/functional_tests/CMakeLists.txt18
-rw-r--r--tests/functional_tests/cpu_power_test.cpp112
-rwxr-xr-xtests/functional_tests/mining.py94
-rw-r--r--tests/functional_tests/transactions_flow_test.cpp1
-rwxr-xr-xtests/functional_tests/util_resources.py52
-rw-r--r--tests/fuzz/cold-outputs.cpp2
-rw-r--r--tests/fuzz/levin.cpp4
-rw-r--r--tests/net_load_tests/net_load_tests.h2
-rw-r--r--tests/net_load_tests/srv.cpp2
-rw-r--r--tests/performance_tests/performance_tests.h1
-rw-r--r--tests/unit_tests/bulletproofs.cpp1
-rw-r--r--tests/unit_tests/crypto.cpp213
-rw-r--r--tests/unit_tests/epee_boosted_tcp_server.cpp331
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp26
-rw-r--r--tests/unit_tests/epee_serialization.cpp1
-rw-r--r--tests/unit_tests/epee_utils.cpp4
-rw-r--r--tests/unit_tests/hardfork.cpp1
-rw-r--r--tests/unit_tests/levin.cpp117
-rw-r--r--tests/unit_tests/net.cpp16
-rw-r--r--tests/unit_tests/node_server.cpp605
-rw-r--r--tests/unit_tests/output_selection.cpp2
-rw-r--r--tests/unit_tests/wipeable_string.cpp18
-rw-r--r--tests/unit_tests/zmq_rpc.cpp1
26 files changed, 1560 insertions, 78 deletions
diff --git a/tests/README.md b/tests/README.md
index f6dd25ead..c4ad1ce37 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -52,6 +52,11 @@ To run the same tests on a release build, replace `debug` with `release`.
[TODO]
Functional tests are located under the `tests/functional` directory.
+Building all the tests requires installing the following dependencies:
+```bash
+pip install requests psutil monotonic
+```
+
First, run a regtest daemon in the offline mode and with a fixed difficulty:
```bash
monerod --regtest --offline --fixed-difficulty 1
diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp
index d0b55dcf4..d19bdd1f9 100644
--- a/tests/core_tests/transaction_tests.cpp
+++ b/tests/core_tests/transaction_tests.cpp
@@ -78,8 +78,6 @@ bool test_transaction_generation_and_ring_signature()
tx_source_entry& src = sources.back();
src.amount = 70368744177663;
{
- tx_output_entry oe;
-
src.push_output(0, boost::get<txout_to_key>(tx_mine_1.vout[0].target).key, src.amount);
src.push_output(1, boost::get<txout_to_key>(tx_mine_2.vout[0].target).key, src.amount);
diff --git a/tests/core_tests/tx_pool.cpp b/tests/core_tests/tx_pool.cpp
index 1e496f3da..166eb6075 100644
--- a/tests/core_tests/tx_pool.cpp
+++ b/tests/core_tests/tx_pool.cpp
@@ -165,9 +165,6 @@ bool txpool_double_spend_base::timestamp_change_pause(cryptonote::core& /*c*/, s
bool txpool_double_spend_base::check_changed(cryptonote::core& c, const size_t ev_index, relay_test condition)
{
- const std::size_t public_hash_count = m_broadcasted_hashes.size();
- const std::size_t all_hash_count = m_all_hashes.size();
-
const std::size_t new_broadcasted_hash_count = m_broadcasted_hashes.size() + unsigned(condition == relay_test::broadcasted);
const std::size_t new_all_hash_count = m_all_hashes.size() + unsigned(condition == relay_test::hidden) + unsigned(condition == relay_test::no_relay);
@@ -393,7 +390,7 @@ bool txpool_double_spend_base::check_changed(cryptonote::core& c, const size_t e
}
}
- for (const std::pair<crypto::hash, uint64_t>& hash : m_all_hashes)
+ for (const std::pair<const crypto::hash, uint64_t>& hash : m_all_hashes)
{
cryptonote::blobdata tx_blob{};
if (!c.get_pool_transaction(hash.first, tx_blob, cryptonote::relay_category::all))
@@ -411,7 +408,7 @@ bool txpool_double_spend_base::check_changed(cryptonote::core& c, const size_t e
for (const crypto::hash& hash : m_no_relay_hashes)
difference.erase(hash);
- for (const std::pair<crypto::hash, uint64_t>& hash : difference)
+ for (const std::pair<const crypto::hash, uint64_t>& hash : difference)
{
if (c.pool_has_tx(hash.first))
{
diff --git a/tests/functional_tests/CMakeLists.txt b/tests/functional_tests/CMakeLists.txt
index 462fd4b77..337097a34 100644
--- a/tests/functional_tests/CMakeLists.txt
+++ b/tests/functional_tests/CMakeLists.txt
@@ -64,16 +64,18 @@ target_link_libraries(make_test_signature
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
-execute_process(COMMAND ${PYTHON_EXECUTABLE} "-c" "import requests; print('OK')" OUTPUT_VARIABLE REQUESTS_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
+monero_add_minimal_executable(cpu_power_test cpu_power_test.cpp)
+find_program(PYTHON3_FOUND python3 REQUIRED)
+
+execute_process(COMMAND ${PYTHON3_FOUND} "-c" "import requests; import psutil; import monotonic; print('OK')" OUTPUT_VARIABLE REQUESTS_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
if (REQUESTS_OUTPUT STREQUAL "OK")
add_test(
NAME functional_tests_rpc
- COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/functional_tests_rpc.py" "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" all)
+ COMMAND ${PYTHON3_FOUND} "${CMAKE_CURRENT_SOURCE_DIR}/functional_tests_rpc.py" "${PYTHON3_FOUND}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" all)
+ add_test(
+ NAME check_missing_rpc_methods
+ COMMAND ${PYTHON3_FOUND} "${CMAKE_CURRENT_SOURCE_DIR}/check_missing_rpc_methods.py" "${CMAKE_SOURCE_DIR}")
else()
- message(WARNING "functional_tests_rpc skipped, needs the 'requests' python module")
- set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc)
+ message(WARNING "functional_tests_rpc and check_missing_rpc_methods skipped, needs the 'requests', 'psutil' and 'monotonic' python modules")
+ set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc check_missing_rpc_methods)
endif()
-
-add_test(
- NAME check_missing_rpc_methods
- COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/check_missing_rpc_methods.py" "${CMAKE_SOURCE_DIR}")
diff --git a/tests/functional_tests/cpu_power_test.cpp b/tests/functional_tests/cpu_power_test.cpp
new file mode 100644
index 000000000..54c4bfc9f
--- /dev/null
+++ b/tests/functional_tests/cpu_power_test.cpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2014-2021, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+const char * descr =
+"This program prints the time (ms) needed to calculate a mathematical challenge. It's purpose \n\
+is to be able to use the result to compare the CPU power available on the machine it's being executed \n\
+and under the given circumstances, which can differ for the same machine. For example: \n\
+The printed value will be different when using 2 of 2 cores, when there an another process \n\
+running on one of the cores core, and when no other intense process running. \n\
+ \n\
+The program expects a one argument: a numerical value of the threads to start the calculations on. \n\
+ \n\
+Prints: \n\
+Time to calculate a mathematical challenge in MILLISECONDS. \n\
+ \n\
+Returns: \n\
+0 on success, \n\
+1 on a missing argument, \n\
+2 on an incorrect format of the argument.\n";
+
+#include <iostream>
+#include <future>
+#include <vector>
+#include <sstream>
+#include <chrono>
+
+using namespace std;
+
+/**
+Uses Leibniz Formula for Pi.
+https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80
+*/
+static double calcPi(const size_t max_iter)
+{
+ const double n = 4;
+ double pi = 0;
+ double d = 1;
+ for (size_t i = 1; i < max_iter; ++i)
+ {
+ const double a = 2.0 * (i % 2) - 1.0;
+ pi += a * n / d;
+ d += 2;
+ }
+ return pi;
+}
+
+int main(int argc, const char ** argv)
+{
+ const size_t max_iter = 1e9;
+ if (argc < 2)
+ {
+ cout << "Please pass the number of threads to run.\n";
+
+ cout << '\n' << descr << '\n';
+ return 1;
+ }
+
+ // Convert argument to an integer.
+ int numThreads = 1;
+ const char * numThreadsStr = argv[1];
+ std::istringstream iss(numThreadsStr);
+ if (! (iss >> numThreads) )
+ {
+ cout << "Incorrect format of number of threads = '" << numThreadsStr << "'\n";
+ return 2;
+ }
+ // Run the calculation in parallel.
+ std::vector<std::future<double>> futures;
+ for(int i = 0; i < numThreads; ++i)
+ {
+ futures.push_back(std::async(calcPi, max_iter));
+ }
+
+ // Start measuring the time.
+ const std::chrono::steady_clock::time_point tbegin = std::chrono::steady_clock::now();
+ for(auto & e : futures)
+ {
+ e.get();
+ }
+ // Stop measuring the time.
+ const std::chrono::steady_clock::time_point tend = std::chrono::steady_clock::now();
+
+ // Print the measured duration.
+ cout << std::chrono::duration_cast<std::chrono::milliseconds>(tend - tbegin).count() << std::endl;
+ return 0;
+}
+
diff --git a/tests/functional_tests/mining.py b/tests/functional_tests/mining.py
index 1eb6b0ba7..cb2fd66e1 100755
--- a/tests/functional_tests/mining.py
+++ b/tests/functional_tests/mining.py
@@ -31,6 +31,10 @@
from __future__ import print_function
import time
import os
+import math
+import monotonic
+import util_resources
+import multiprocessing
"""Test daemon mining RPC calls
@@ -71,12 +75,20 @@ class MiningTest():
def mine(self, via_daemon):
print("Test mining via " + ("daemon" if via_daemon else "wallet"))
+ cores_init = multiprocessing.cpu_count() # RX init uses all cores
+ cores_mine = 1 # Mining uses a parametric number of cores
+ time_pi_single_cpu = self.measure_cpu_power_get_time(cores_mine)
+ time_pi_all_cores = self.measure_cpu_power_get_time(cores_init)
+ # This is the last measurement, since it takes very little time and can be placed timewise-closer to the mining itself.
+ available_ram = self.get_available_ram() # So far no ideas how to use this var, other than printing it
+
+ start = monotonic.monotonic()
daemon = Daemon()
wallet = Wallet()
# check info/height/balance before generating blocks
res_info = daemon.get_info()
- prev_height = res_info.height
+ initial_height = res_info.height
res_getbalance = wallet.get_balance()
prev_balance = res_getbalance.balance
@@ -85,29 +97,71 @@ class MiningTest():
if via_daemon:
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1)
else:
- res = wallet.start_mining(threads_count = 1)
+ res = wallet.start_mining(threads_count = cores_mine)
res_status = daemon.mining_status()
assert res_status.active == True
- assert res_status.threads_count == 1
+ assert res_status.threads_count == cores_mine
assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'
assert res_status.is_background_mining_enabled == False
assert res_status.block_reward >= 600000000000
# wait till we mined a few of them
- target_height = prev_height + 5
- height = prev_height
- timeout = 60 # randomx is slow to init
+ target_height = initial_height + 5
+ height = initial_height
+
+ """
+ Randomx init has high variance on CI machines due to noisy neighbors,
+ taking up resources in parallel (including by our own jobs).
+
+ Mining is organized in the following scheme:
+ 1) first loop's pass: RandomX init and mining
+ 2) every next pass: only mining
+ Pass 1) takes much more time than pass 2)
+ Pass 1) uses all cores, pass 2) just one (currently)
+ For the above reasons both passes need separate timeouts and adjustments.
+ After the first pass, the timeout is being reset to a lower value.
+ """
+
+ def calc_timeout(seconds_constant, time_pi, cores):
+ """
+ The time it took to calculate pi under certain conditions
+ is proportional to the time it will take to calculate the real job.
+
+ The number of cores used decreases the time almost linearly.
+ """
+ timeout = float(seconds_constant) * time_pi / float(cores)
+ return timeout
+
+ timeout_base_init = 60 # RX init needs more time
+ timeout_base_mine = 20
+ timeout_init = calc_timeout(timeout_base_init, time_pi_all_cores, cores_init)
+ timeout_mine = calc_timeout(timeout_base_mine, time_pi_single_cpu, cores_mine)
+
+ msg = "Timeout for {} adjusted for the currently available CPU power, is {:.1f} s"
+ print(msg.format("init, ", timeout_init))
+ print(msg.format("mining,", timeout_mine))
+
+ timeout = timeout_init
+ rx_inited = False # Gets initialized in the first pass of the below loop
while height < target_height:
seen_height = height
- for _ in range(timeout):
+ for _ in range(int(math.ceil(timeout))):
time.sleep(1)
+ seconds_passed = monotonic.monotonic() - start
height = daemon.get_info().height
if height > seen_height:
break
else:
- assert False, 'Failed to mine successor to block %d (initial block = %d)' % (seen_height, prev_height)
- timeout = 10
+ assert False, 'Failed to mine successor to block %d (initial block = %d) after %d s. RX initialized = %r' % (seen_height, initial_height, round(seconds_passed), rx_inited)
+ if not rx_inited:
+ rx_inited = True
+ timeout = timeout_mine # Resetting the timeout after first mined block and RX init
+ self.print_time_taken(start, "RX init + mining 1st block")
+ else:
+ self.print_time_taken(start, "mining iteration")
+
+ self.print_time_taken(start, "mining total")
if via_daemon:
res = daemon.stop_mining()
@@ -123,7 +177,7 @@ class MiningTest():
wallet.refresh()
res_getbalance = wallet.get_balance()
balance = res_getbalance.balance
- assert balance >= prev_balance + (new_height - prev_height) * 600000000000
+ assert balance >= prev_balance + (new_height - initial_height) * 600000000000
if via_daemon:
res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1, do_background_mining = True)
@@ -143,6 +197,22 @@ class MiningTest():
res = wallet.stop_mining()
res_status = daemon.mining_status()
assert res_status.active == False
+
+ def measure_cpu_power_get_time(self, cores):
+ print("Measuring the currently available CPU power...")
+ time_pi = util_resources.get_time_pi_seconds(cores)
+ print("Time taken to calculate Pi on {} core(s) was {:.2f} s.".format(cores, time_pi))
+ return time_pi
+
+ def get_available_ram(self):
+ available_ram = util_resources.available_ram_gb()
+ threshold_ram = 3
+ print("Available RAM =", round(available_ram, 1), "GB")
+ if available_ram < threshold_ram:
+ print("Warning! Available RAM =", round(available_ram, 1),
+ "GB is less than the reasonable threshold =", threshold_ram,
+ ". The RX init might exceed the calculated timeout.")
+ return available_ram
def submitblock(self):
print("Test submitblock")
@@ -170,6 +240,10 @@ class MiningTest():
res = daemon.get_height()
assert res.height == height + i + 1
assert res.hash == block_hash
+
+ def print_time_taken(self, start, msg_context):
+ seconds_passed = monotonic.monotonic() - start
+ print("Time taken for", msg_context, "=", round(seconds_passed, 1), "s.")
def test_randomx(self):
print("Test RandomX")
diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp
index cec6825f5..3f5f90d3b 100644
--- a/tests/functional_tests/transactions_flow_test.cpp
+++ b/tests/functional_tests/transactions_flow_test.cpp
@@ -41,7 +41,6 @@ using namespace cryptonote;
namespace
{
uint64_t const TEST_FEE = 5000000000; // 5 * 10^9
- uint64_t const TEST_DUST_THRESHOLD = 5000000000; // 5 * 10^9
}
std::string generate_random_wallet_name()
diff --git a/tests/functional_tests/util_resources.py b/tests/functional_tests/util_resources.py
new file mode 100755
index 000000000..e45122e66
--- /dev/null
+++ b/tests/functional_tests/util_resources.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2021 The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+ Help determine how much CPU power is available at the given time
+ by running numerical calculations
+"""
+
+from __future__ import print_function
+import subprocess
+import psutil
+
+def available_ram_gb():
+ ram_bytes = psutil.virtual_memory().available
+ kilo = 1024.0
+ ram_gb = ram_bytes / kilo**3
+ return ram_gb
+
+def get_time_pi_seconds(cores):
+ app_path = './cpu_power_test'
+ time_calc = subprocess.check_output([app_path, str(cores)])
+ decoded = time_calc.decode('utf-8')
+ miliseconds = int(decoded)
+
+ return miliseconds / 1000.0
diff --git a/tests/fuzz/cold-outputs.cpp b/tests/fuzz/cold-outputs.cpp
index 2698a36ba..bd298eb71 100644
--- a/tests/fuzz/cold-outputs.cpp
+++ b/tests/fuzz/cold-outputs.cpp
@@ -51,7 +51,7 @@ END_INIT_SIMPLE_FUZZER()
BEGIN_SIMPLE_FUZZER()
std::string s((const char*)buf, len);
- std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
+ std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs;
std::stringstream iss;
iss << s;
binary_archive<false> ar(iss);
diff --git a/tests/fuzz/levin.cpp b/tests/fuzz/levin.cpp
index 78b7b6863..209a75221 100644
--- a/tests/fuzz/levin.cpp
+++ b/tests/fuzz/levin.cpp
@@ -68,13 +68,13 @@ namespace
{
}
- virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
- buff_out = m_invoke_out_buf.clone();
+ buff_out.write(epee::to_span(m_invoke_out_buf));
return m_return_code;
}
diff --git a/tests/net_load_tests/net_load_tests.h b/tests/net_load_tests/net_load_tests.h
index baab07d31..59eef7bd1 100644
--- a/tests/net_load_tests/net_load_tests.h
+++ b/tests/net_load_tests/net_load_tests.h
@@ -67,7 +67,7 @@ namespace net_load_tests
{
}
- virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, test_connection_context& context)
{
//m_invoke_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex);
diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp
index 84d97ebd4..fabe14f49 100644
--- a/tests/net_load_tests/srv.cpp
+++ b/tests/net_load_tests/srv.cpp
@@ -169,7 +169,7 @@ namespace
LOG_PRINT_L0("Closing connections. Number of opened connections: " << m_tcp_server.get_config_object().get_connections_count());
size_t count = 0;
- bool r = m_tcp_server.get_config_object().foreach_connection([&](test_connection_context& ctx) {
+ m_tcp_server.get_config_object().foreach_connection([&](test_connection_context& ctx) {
if (ctx.m_connection_id != cmd_conn_id)
{
++count;
diff --git a/tests/performance_tests/performance_tests.h b/tests/performance_tests/performance_tests.h
index ae7aabe08..7bedfdd4e 100644
--- a/tests/performance_tests/performance_tests.h
+++ b/tests/performance_tests/performance_tests.h
@@ -215,7 +215,6 @@ void run_test(const std::string &filter, Params &params, const char* test_name)
if (params.stats)
{
uint64_t mins = min / scale;
- uint64_t maxs = max / scale;
uint64_t meds = med / scale;
uint64_t p95s = quantiles[9] / scale;
uint64_t stddevs = stddev / scale;
diff --git a/tests/unit_tests/bulletproofs.cpp b/tests/unit_tests/bulletproofs.cpp
index 7c6e459f5..ee617938c 100644
--- a/tests/unit_tests/bulletproofs.cpp
+++ b/tests/unit_tests/bulletproofs.cpp
@@ -296,7 +296,6 @@ TEST(bulletproof, weight_pruned)
ASSERT_TRUE(tx.version == 2);
ASSERT_FALSE(tx.pruned);
ASSERT_TRUE(rct::is_rct_bulletproof(tx.rct_signatures.type));
- const uint64_t tx_size = bd.size();
const uint64_t tx_weight = cryptonote::get_transaction_weight(tx);
ASSERT_TRUE(parse_and_validate_tx_base_from_blob(bd, pruned_tx));
ASSERT_TRUE(pruned_tx.version == 2);
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index 7ac87ca7c..b550b35b0 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -33,6 +33,7 @@
#include <string>
#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "cryptonote_basic/merge_mining.h"
namespace
{
@@ -99,3 +100,215 @@ TEST(Crypto, verify_32)
}
}
}
+
+TEST(Crypto, tree_branch)
+{
+ crypto::hash inputs[6];
+ crypto::hash branch[8];
+ crypto::hash root, root2;
+ size_t depth;
+ uint32_t path, path2;
+
+ auto hasher = [](const crypto::hash &h0, const crypto::hash &h1) -> crypto::hash
+ {
+ char buffer[64];
+ memcpy(buffer, &h0, 32);
+ memcpy(buffer + 32, &h1, 32);
+ crypto::hash res;
+ cn_fast_hash(buffer, 64, res);
+ return res;
+ };
+
+ for (int n = 0; n < 6; ++n)
+ {
+ memset(&inputs[n], 0, 32);
+ inputs[n].data[0] = n + 1;
+ }
+
+ // empty
+ ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 0, crypto::null_hash.data, (char(*)[32])branch, &depth, &path));
+
+ // one, matching
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 1, inputs[0].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_EQ(depth, 0);
+ ASSERT_EQ(path, 0);
+ ASSERT_TRUE(crypto::tree_path(1, 0, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 1, root.data);
+ ASSERT_EQ(root, inputs[0]);
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // one, not found
+ ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 1, inputs[1].data, (char(*)[32])branch, &depth, &path));
+
+ // two, index 0
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[0].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_EQ(depth, 1);
+ ASSERT_EQ(path, 0);
+ ASSERT_TRUE(crypto::tree_path(2, 0, &path2));
+ ASSERT_EQ(path, path2);
+ ASSERT_EQ(branch[0], inputs[1]);
+ crypto::tree_hash((const char(*)[32])inputs, 2, root.data);
+ ASSERT_EQ(root, hasher(inputs[0], inputs[1]));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // two, index 1
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[1].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_EQ(depth, 1);
+ ASSERT_EQ(path, 1);
+ ASSERT_TRUE(crypto::tree_path(2, 1, &path2));
+ ASSERT_EQ(path, path2);
+ ASSERT_EQ(branch[0], inputs[0]);
+ crypto::tree_hash((const char(*)[32])inputs, 2, root.data);
+ ASSERT_EQ(root, hasher(inputs[0], inputs[1]));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // two, not found
+ ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 2, inputs[2].data, (char(*)[32])branch, &depth, &path));
+
+ // a b c 0
+ // x y
+ // z
+
+ // three, index 0
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[0].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 1);
+ ASSERT_LE(depth, 2);
+ ASSERT_TRUE(crypto::tree_path(3, 0, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
+ ASSERT_EQ(root, hasher(inputs[0], hasher(inputs[1], inputs[2])));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // three, index 1
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[1].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 1);
+ ASSERT_LE(depth, 2);
+ ASSERT_TRUE(crypto::tree_path(3, 1, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
+ ASSERT_EQ(root, hasher(inputs[0], hasher(inputs[1], inputs[2])));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // three, index 2
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[2].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 1);
+ ASSERT_LE(depth, 2);
+ ASSERT_TRUE(crypto::tree_path(3, 2, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 3, root.data);
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::tree_branch_hash(inputs[2].data, (const char(*)[32])branch, depth, path, root2.data));
+ ASSERT_EQ(root, root2);
+
+ // three, not found
+ ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 3, inputs[3].data, (char(*)[32])branch, &depth, &path));
+
+ // a b c d e 0 0 0
+ // x y
+ // z
+ // w
+
+ // five, index 0
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[0].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 2);
+ ASSERT_LE(depth, 3);
+ ASSERT_TRUE(crypto::tree_path(5, 0, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // five, index 1
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[1].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 2);
+ ASSERT_LE(depth, 3);
+ ASSERT_TRUE(crypto::tree_path(5, 1, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // five, index 2
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[2].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 2);
+ ASSERT_LE(depth, 3);
+ ASSERT_TRUE(crypto::tree_path(5, 2, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ // five, index 4
+ ASSERT_TRUE(crypto::tree_branch((const char(*)[32])inputs, 5, inputs[4].data, (char(*)[32])branch, &depth, &path));
+ ASSERT_GE(depth, 2);
+ ASSERT_LE(depth, 3);
+ ASSERT_TRUE(crypto::tree_path(5, 4, &path2));
+ ASSERT_EQ(path, path2);
+ crypto::tree_hash((const char(*)[32])inputs, 5, root.data);
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[0].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[1].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[2].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[3].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_TRUE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path));
+
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth - 1, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth + 1, path));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 1));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 2));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 3));
+ ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])(branch + 1), depth, path));
+
+ // five, not found
+ ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 5, crypto::null_hash.data, (char(*)[32])branch, &depth, &path));
+
+ // depth encoding roundtrip
+ for (uint32_t n_chains = 1; n_chains <= 65; ++n_chains)
+ {
+ for (uint32_t nonce = 0; nonce < 1024; ++nonce)
+ {
+ const uint32_t depth = cryptonote::encode_mm_depth(n_chains, nonce);
+ uint32_t n_chains_2, nonce_2;
+ ASSERT_TRUE(cryptonote::decode_mm_depth(depth, n_chains_2, nonce_2));
+ ASSERT_EQ(n_chains, n_chains_2);
+ ASSERT_EQ(nonce, nonce_2);
+ }
+ }
+}
diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp
index 71098f612..84fc0a29b 100644
--- a/tests/unit_tests/epee_boosted_tcp_server.cpp
+++ b/tests/unit_tests/epee_boosted_tcp_server.cpp
@@ -37,6 +37,7 @@
#include "include_base_utils.h"
#include "string_tools.h"
#include "net/abstract_tcp_server2.h"
+#include "net/levin_protocol_handler_async.h"
namespace
{
@@ -132,3 +133,333 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant)
ASSERT_TRUE(srv.timed_wait_server_stop(5 * 1000));
ASSERT_TRUE(srv.deinit_server());
}
+
+
+TEST(test_epee_connection, test_lifetime)
+{
+ struct context_t: epee::net_utils::connection_context_base {
+ static constexpr size_t get_max_bytes(int) noexcept { return -1; }
+ static constexpr int handshake_command() noexcept { return 1001; }
+ static constexpr bool handshake_complete() noexcept { return true; }
+ };
+
+ using functional_obj_t = std::function<void ()>;
+ struct command_handler_t: epee::levin::levin_commands_handler<context_t> {
+ size_t delay;
+ functional_obj_t on_connection_close_f;
+ command_handler_t(size_t delay = 0,
+ functional_obj_t on_connection_close_f = nullptr
+ ):
+ delay(delay),
+ on_connection_close_f(on_connection_close_f)
+ {}
+ virtual int invoke(int, const epee::span<const uint8_t>, epee::byte_stream&, context_t&) override { epee::misc_utils::sleep_no_w(delay); return {}; }
+ virtual int notify(int, const epee::span<const uint8_t>, context_t&) override { return {}; }
+ virtual void callback(context_t&) override {}
+ virtual void on_connection_new(context_t&) override {}
+ virtual void on_connection_close(context_t&) override {
+ if (on_connection_close_f)
+ on_connection_close_f();
+ }
+ virtual ~command_handler_t() override {}
+ static void destroy(epee::levin::levin_commands_handler<context_t>* ptr) { delete ptr; }
+ };
+
+ using handler_t = epee::levin::async_protocol_handler<context_t>;
+ using connection_t = epee::net_utils::connection<handler_t>;
+ using connection_ptr = boost::shared_ptr<connection_t>;
+ using shared_state_t = typename connection_t::shared_state;
+ using shared_state_ptr = std::shared_ptr<shared_state_t>;
+ using shared_states_t = std::vector<shared_state_ptr>;
+ using tag_t = boost::uuids::uuid;
+ using tags_t = std::vector<tag_t>;
+ using io_context_t = boost::asio::io_service;
+ using endpoint_t = boost::asio::ip::tcp::endpoint;
+ using work_t = boost::asio::io_service::work;
+ using work_ptr = std::shared_ptr<work_t>;
+ using workers_t = std::vector<std::thread>;
+ using server_t = epee::net_utils::boosted_tcp_server<handler_t>;
+ using lock_t = std::mutex;
+ using lock_guard_t = std::lock_guard<lock_t>;
+ using connection_weak_ptr = boost::weak_ptr<connection_t>;
+ struct shared_conn_t {
+ lock_t lock;
+ connection_weak_ptr conn;
+ };
+ using shared_conn_ptr = std::shared_ptr<shared_conn_t>;
+
+ io_context_t io_context;
+ work_ptr work(std::make_shared<work_t>(io_context));
+
+ workers_t workers;
+ while (workers.size() < 4) {
+ workers.emplace_back([&io_context]{
+ io_context.run();
+ });
+ }
+
+ endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262);
+ server_t server(epee::net_utils::e_connection_type_P2P);
+ server.init_server(endpoint.port(),
+ endpoint.address().to_string(),
+ 0,
+ "",
+ false,
+ true,
+ epee::net_utils::ssl_support_t::e_ssl_support_disabled
+ );
+ server.run_server(2, false);
+ server.get_config_shared()->set_handler(new command_handler_t, &command_handler_t::destroy);
+
+ io_context.post([&io_context, &work, &endpoint, &server]{
+ auto scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&work]{
+ work.reset();
+ });
+
+ shared_state_ptr shared_state(std::make_shared<shared_state_t>());
+ shared_state->set_handler(new command_handler_t, &command_handler_t::destroy);
+
+ auto create_connection = [&io_context, &endpoint, &shared_state] {
+ connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ context_t context;
+ conn->get_context(context);
+ auto tag = context.m_connection_id;
+ return tag;
+ };
+
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ auto tag = create_connection();
+ ASSERT_TRUE(shared_state->get_connections_count() == 1);
+ bool success = shared_state->for_connection(tag, [shared_state](context_t& context){
+ shared_state->close(context.m_connection_id);
+ context.m_remote_address.get_zone();
+ return true;
+ });
+ ASSERT_TRUE(success);
+
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ constexpr auto N = 8;
+ tags_t tags(N);
+ for(auto &t: tags)
+ t = create_connection();
+ ASSERT_TRUE(shared_state->get_connections_count() == N);
+ size_t index = 0;
+ success = shared_state->foreach_connection([&index, shared_state, &tags, &create_connection](context_t& context){
+ if (!index)
+ for (const auto &t: tags)
+ shared_state->close(t);
+
+ shared_state->close(context.m_connection_id);
+ context.m_remote_address.get_zone();
+ ++index;
+
+ for(auto i = 0; i < N; ++i)
+ create_connection();
+ return true;
+ });
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(index == N);
+ ASSERT_TRUE(shared_state->get_connections_count() == N * N);
+
+ index = 0;
+ success = shared_state->foreach_connection([&index, shared_state](context_t& context){
+ shared_state->close(context.m_connection_id);
+ context.m_remote_address.get_zone();
+ ++index;
+ return true;
+ });
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(index == N * N);
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+
+ while (shared_state->sock_count);
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ constexpr auto DELAY = 30;
+ constexpr auto TIMEOUT = 1;
+ server.get_config_shared()->set_handler(new command_handler_t(DELAY), &command_handler_t::destroy);
+ for (auto i = 0; i < N; ++i) {
+ tag = create_connection();
+ ASSERT_TRUE(shared_state->get_connections_count() == 1);
+ success = shared_state->invoke_async(1, epee::levin::message_writer{}, tag, [](int, const epee::span<const uint8_t>, context_t&){}, TIMEOUT);
+ ASSERT_TRUE(success);
+ while (shared_state->sock_count == 1) {
+ success = shared_state->foreach_connection([&shared_state, &tag](context_t&){
+ return shared_state->request_callback(tag);
+ });
+ ASSERT_TRUE(success);
+ }
+ shared_state->close(tag);
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ }
+
+ while (shared_state->sock_count);
+ constexpr auto ZERO_DELAY = 0;
+ size_t counter = 0;
+ shared_state->set_handler(new command_handler_t(ZERO_DELAY,
+ [&counter]{
+ ASSERT_TRUE(counter++ == 0);
+ }
+ ),
+ &command_handler_t::destroy
+ );
+ connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ ASSERT_TRUE(shared_state->get_connections_count() == 1);
+ shared_state->del_out_connections(1);
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ conn.reset();
+
+ while (shared_state->sock_count);
+ shared_conn_ptr shared_conn(std::make_shared<shared_conn_t>());
+ shared_state->set_handler(new command_handler_t(ZERO_DELAY,
+ [shared_state, shared_conn]{
+ {
+ connection_ptr conn;
+ {
+ lock_guard_t guard(shared_conn->lock);
+ conn = std::move(shared_conn->conn.lock());
+ }
+ if (conn)
+ conn->cancel();
+ }
+ const auto success = shared_state->foreach_connection([](context_t&){
+ return true;
+ });
+ ASSERT_TRUE(success);
+ }
+ ),
+ &command_handler_t::destroy
+ );
+ for (auto i = 0; i < N; ++i) {
+ {
+ connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ lock_guard_t guard(shared_conn->lock);
+ shared_conn->conn = conn;
+ }
+ ASSERT_TRUE(shared_state->get_connections_count() == 1);
+ shared_state->del_out_connections(1);
+ ASSERT_TRUE(shared_state->get_connections_count() == 0);
+ }
+
+ shared_states_t shared_states;
+ while (shared_states.size() < 2) {
+ shared_states.emplace_back(std::make_shared<shared_state_t>());
+ shared_states.back()->set_handler(new command_handler_t(ZERO_DELAY,
+ [&shared_states]{
+ for (auto &s: shared_states) {
+ auto success = s->foreach_connection([](context_t&){
+ return true;
+ });
+ ASSERT_TRUE(success);
+ }
+ }
+ ),
+ &command_handler_t::destroy
+ );
+ }
+ workers_t workers;
+
+ for (auto &s: shared_states) {
+ workers.emplace_back([&io_context, &s, &endpoint]{
+ for (auto i = 0; i < N * N; ++i) {
+ connection_ptr conn(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ io_context.post([conn]{
+ conn->cancel();
+ });
+ conn.reset();
+ s->del_out_connections(1);
+ while (s->sock_count);
+ }
+ });
+ }
+ for (;workers.size(); workers.pop_back())
+ workers.back().join();
+
+ for (auto &s: shared_states) {
+ workers.emplace_back([&io_context, &s, &endpoint]{
+ for (auto i = 0; i < N * N; ++i) {
+ connection_ptr conn(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ conn->cancel();
+ while (conn.use_count() > 1);
+ s->foreach_connection([&io_context, &s, &endpoint, &conn](context_t& context){
+ conn.reset(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ conn->cancel();
+ while (conn.use_count() > 1);
+ conn.reset();
+ return true;
+ });
+ while (s->sock_count);
+ }
+ });
+ }
+ for (;workers.size(); workers.pop_back())
+ workers.back().join();
+
+ for (auto &s: shared_states) {
+ workers.emplace_back([&io_context, &s, &endpoint]{
+ for (auto i = 0; i < N; ++i) {
+ connection_ptr conn(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ context_t context;
+ conn->get_context(context);
+ auto tag = context.m_connection_id;
+ conn->cancel();
+ while (conn.use_count() > 1);
+ s->for_connection(tag, [&io_context, &s, &endpoint, &conn](context_t& context){
+ conn.reset(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ conn->cancel();
+ while (conn.use_count() > 1);
+ conn.reset();
+ return true;
+ });
+ while (s->sock_count);
+ }
+ });
+ }
+ for (;workers.size(); workers.pop_back())
+ workers.back().join();
+
+ for (auto &s: shared_states) {
+ workers.emplace_back([&io_context, &s, &endpoint]{
+ for (auto i = 0; i < N; ++i) {
+ connection_ptr conn(new connection_t(io_context, s, {}, {}));
+ conn->socket().connect(endpoint);
+ conn->start({}, {});
+ context_t context;
+ conn->get_context(context);
+ auto tag = context.m_connection_id;
+ io_context.post([conn]{
+ conn->cancel();
+ });
+ conn.reset();
+ s->close(tag);
+ while (s->sock_count);
+ }
+ });
+ }
+ for (;workers.size(); workers.pop_back())
+ workers.back().join();
+
+ });
+
+ for (auto& w: workers) {
+ w.join();
+ }
+ server.send_stop_signal();
+ server.timed_wait_server_stop(5 * 1000);
+ server.deinit_server();
+}
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index a499fa608..d9de99b8b 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -59,13 +59,13 @@ namespace
{
}
- virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
- buff_out = m_invoke_out_buf.clone();
+ buff_out.write(epee::to_span(m_invoke_out_buf));
return m_return_code;
}
@@ -434,8 +434,11 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
const int expected_command = 4673261;
const std::string in_data(256, 'e');
+ epee::levin::message_writer message{};
+ message.buffer.write(epee::to_span(in_data));
+
const epee::byte_slice noise = epee::levin::make_noise_notify(1024);
- const epee::byte_slice notify = epee::levin::make_notify(expected_command, epee::strspan<std::uint8_t>(in_data));
+ const epee::byte_slice notify = message.finalize_notify(expected_command);
test_connection_ptr conn = create_connection();
@@ -468,11 +471,16 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
const int expected_command = 4673261;
const int expected_fragmented_command = 46732;
const std::string in_data(256, 'e');
- std::string in_fragmented_data(1024 * 4, 'c');
+
+ epee::levin::message_writer message{};
+ message.buffer.write(epee::to_span(in_data));
+
+ epee::levin::message_writer in_fragmented_data;
+ in_fragmented_data.buffer.put_n('c', 1024 * 4);
const epee::byte_slice noise = epee::levin::make_noise_notify(1024);
- const epee::byte_slice notify = epee::levin::make_notify(expected_command, epee::strspan<std::uint8_t>(in_data));
- epee::byte_slice fragmented = epee::levin::make_fragmented_notify(noise, expected_fragmented_command, epee::strspan<std::uint8_t>(in_fragmented_data));
+ const epee::byte_slice notify = message.finalize_notify(expected_command);
+ epee::byte_slice fragmented = epee::levin::make_fragmented_notify(noise.size(), expected_fragmented_command, std::move(in_fragmented_data));
EXPECT_EQ(5u, fragmented.size() / 1024);
EXPECT_EQ(0u, fragmented.size() % 1024);
@@ -497,11 +505,13 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
ASSERT_TRUE(conn->m_protocol_handler.handle_recv(next.data(), next.size()));
}
- in_fragmented_data.resize(((1024 - sizeof(epee::levin::bucket_head2)) * 5) - sizeof(epee::levin::bucket_head2)); // add padding zeroes
+ std::string compare_buffer(1024 * 4, 'c');
+ compare_buffer.resize(((1024 - sizeof(epee::levin::bucket_head2)) * 5) - sizeof(epee::levin::bucket_head2)); // add padding zeroes
+
ASSERT_EQ(4u, m_commands_handler.notify_counter());
ASSERT_EQ(0u, m_commands_handler.invoke_counter());
ASSERT_EQ(expected_fragmented_command, m_commands_handler.last_command());
- ASSERT_EQ(in_fragmented_data, m_commands_handler.last_in_buf());
+ ASSERT_EQ(compare_buffer, m_commands_handler.last_in_buf());
ASSERT_EQ(0u, conn->send_counter());
ASSERT_TRUE(conn->last_send_data().empty());
diff --git a/tests/unit_tests/epee_serialization.cpp b/tests/unit_tests/epee_serialization.cpp
index cade16f0d..95a2b6ecd 100644
--- a/tests/unit_tests/epee_serialization.cpp
+++ b/tests/unit_tests/epee_serialization.cpp
@@ -30,6 +30,7 @@
#include <gtest/gtest.h>
#include "storages/portable_storage.h"
+#include "span.h"
TEST(epee_binary, two_keys)
{
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 256f8c3c2..cbe3c61b1 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -1115,11 +1115,13 @@ TEST(ByteStream, ToByteSlice)
epee::byte_stream stream;
+ stream.reserve(128*1024);
stream.write(source);
EXPECT_EQ(sizeof(source), stream.size());
+ EXPECT_EQ(128*1024, stream.capacity());
EXPECT_TRUE(equal(source, byte_span{stream.data(), stream.size()}));
- const epee::byte_slice slice{std::move(stream)};
+ const epee::byte_slice slice{std::move(stream), true};
EXPECT_EQ(0u, stream.size());
EXPECT_EQ(0u, stream.available());
EXPECT_EQ(0u, stream.capacity());
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index 6d7e9a8aa..912651de4 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -432,7 +432,6 @@ TEST(voting, info)
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
static const uint8_t block_versions[] = { 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 };
- static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
static const uint8_t expected_thresholds[] = { 0, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 2 };
for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) {
diff --git a/tests/unit_tests/levin.cpp b/tests/unit_tests/levin.cpp
index 53a7f7b67..30d6f8133 100644
--- a/tests/unit_tests/levin.cpp
+++ b/tests/unit_tests/levin.cpp
@@ -245,9 +245,9 @@ namespace
return out;
}
- virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_slice& buff_out, cryptonote::levin::detail::p2p_context& context) override final
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, epee::byte_stream& buff_out, cryptonote::levin::detail::p2p_context& context) override final
{
- buff_out = nullptr;
+ buff_out.clear();
invoked_.push_back(
{context.m_connection_id, command, std::string{reinterpret_cast<const char*>(in_buff.data()), in_buff.size()}}
);
@@ -384,21 +384,50 @@ TEST(make_header, expect_return)
EXPECT_EQ(0u, header1.m_flags);
}
-TEST(make_notify, empty_payload)
+TEST(message_writer, invoke_with_empty_payload)
{
- const epee::byte_slice message = epee::levin::make_notify(443, nullptr);
+ const epee::byte_slice message = epee::levin::message_writer{}.finalize_invoke(443);
+ const epee::levin::bucket_head2 header =
+ epee::levin::make_header(443, 0, LEVIN_PACKET_REQUEST, true);
+ ASSERT_EQ(sizeof(header), message.size());
+ EXPECT_TRUE(std::memcmp(std::addressof(header), message.data(), sizeof(header)) == 0);
+}
+
+TEST(message_writer, invoke_with_payload)
+{
+ std::string bytes(100, 'a');
+ std::generate(bytes.begin(), bytes.end(), crypto::random_device{});
+
+ epee::levin::message_writer writer{};
+ writer.buffer.write(epee::to_span(bytes));
+
+ const epee::byte_slice message = writer.finalize_invoke(443);
+ const epee::levin::bucket_head2 header =
+ epee::levin::make_header(443, bytes.size(), LEVIN_PACKET_REQUEST, true);
+
+ ASSERT_EQ(sizeof(header) + bytes.size(), message.size());
+ EXPECT_TRUE(std::memcmp(std::addressof(header), message.data(), sizeof(header)) == 0);
+ EXPECT_TRUE(std::memcmp(bytes.data(), message.data() + sizeof(header), bytes.size()) == 0);
+}
+
+TEST(message_writer, notify_with_empty_payload)
+{
+ const epee::byte_slice message = epee::levin::message_writer{}.finalize_notify(443);
const epee::levin::bucket_head2 header =
epee::levin::make_header(443, 0, LEVIN_PACKET_REQUEST, false);
ASSERT_EQ(sizeof(header), message.size());
EXPECT_TRUE(std::memcmp(std::addressof(header), message.data(), sizeof(header)) == 0);
}
-TEST(make_notify, with_payload)
+TEST(message_writer, notify_with_payload)
{
std::string bytes(100, 'a');
std::generate(bytes.begin(), bytes.end(), crypto::random_device{});
- const epee::byte_slice message = epee::levin::make_notify(443, epee::strspan<std::uint8_t>(bytes));
+ epee::levin::message_writer writer{};
+ writer.buffer.write(epee::to_span(bytes));
+
+ const epee::byte_slice message = writer.finalize_notify(443);
const epee::levin::bucket_head2 header =
epee::levin::make_header(443, bytes.size(), LEVIN_PACKET_REQUEST, false);
@@ -407,6 +436,44 @@ TEST(make_notify, with_payload)
EXPECT_TRUE(std::memcmp(bytes.data(), message.data() + sizeof(header), bytes.size()) == 0);
}
+TEST(message_writer, response_with_empty_payload)
+{
+ const epee::byte_slice message = epee::levin::message_writer{}.finalize_response(443, 1);
+ epee::levin::bucket_head2 header =
+ epee::levin::make_header(443, 0, LEVIN_PACKET_RESPONSE, false);
+ header.m_return_code = SWAP32LE(1);
+ ASSERT_EQ(sizeof(header), message.size());
+ EXPECT_TRUE(std::memcmp(std::addressof(header), message.data(), sizeof(header)) == 0);
+}
+
+TEST(message_writer, response_with_payload)
+{
+ std::string bytes(100, 'a');
+ std::generate(bytes.begin(), bytes.end(), crypto::random_device{});
+
+ epee::levin::message_writer writer{};
+ writer.buffer.write(epee::to_span(bytes));
+
+ const epee::byte_slice message = writer.finalize_response(443, 6450);
+ epee::levin::bucket_head2 header =
+ epee::levin::make_header(443, bytes.size(), LEVIN_PACKET_RESPONSE, false);
+ header.m_return_code = SWAP32LE(6450);
+
+ ASSERT_EQ(sizeof(header) + bytes.size(), message.size());
+ EXPECT_TRUE(std::memcmp(std::addressof(header), message.data(), sizeof(header)) == 0);
+ EXPECT_TRUE(std::memcmp(bytes.data(), message.data() + sizeof(header), bytes.size()) == 0);
+}
+
+TEST(message_writer, error)
+{
+ epee::levin::message_writer writer{};
+ writer.buffer.clear();
+
+ EXPECT_THROW(writer.finalize_invoke(0), std::runtime_error);
+ EXPECT_THROW(writer.finalize_notify(0), std::runtime_error);
+ EXPECT_THROW(writer.finalize_response(0, 0), std::runtime_error);
+}
+
TEST(make_noise, invalid)
{
EXPECT_TRUE(epee::levin::make_noise_notify(sizeof(epee::levin::bucket_head2) - 1).empty());
@@ -428,13 +495,13 @@ TEST(make_noise, valid)
TEST(make_fragment, invalid)
{
- EXPECT_TRUE(epee::levin::make_fragmented_notify(nullptr, 0, nullptr).empty());
+ EXPECT_TRUE(epee::levin::make_fragmented_notify(0, 0, epee::levin::message_writer{}).empty());
}
TEST(make_fragment, single)
{
const epee::byte_slice noise = epee::levin::make_noise_notify(1024);
- const epee::byte_slice fragment = epee::levin::make_fragmented_notify(noise, 11, nullptr);
+ const epee::byte_slice fragment = epee::levin::make_fragmented_notify(noise.size(), 11, epee::levin::message_writer{});
const epee::levin::bucket_head2 header =
epee::levin::make_header(11, 1024 - sizeof(epee::levin::bucket_head2), LEVIN_PACKET_REQUEST, false);
@@ -449,8 +516,13 @@ TEST(make_fragment, multiple)
std::string bytes(1024 * 3 - 150, 'a');
std::generate(bytes.begin(), bytes.end(), crypto::random_device{});
+ epee::levin::message_writer message;
+ message.buffer.write(epee::to_span(bytes));
+
const epee::byte_slice noise = epee::levin::make_noise_notify(1024);
- epee::byte_slice fragment = epee::levin::make_fragmented_notify(noise, 114, epee::strspan<std::uint8_t>(bytes));
+ epee::byte_slice fragment = epee::levin::make_fragmented_notify(noise.size(), 114, std::move(message));
+
+ EXPECT_EQ(1024 * 3, fragment.size());
epee::levin::bucket_head2 header =
epee::levin::make_header(0, 1024 - sizeof(epee::levin::bucket_head2), LEVIN_PACKET_BEGIN, false);
@@ -497,6 +569,7 @@ TEST(make_fragment, multiple)
fragment.take_slice(bytes.size());
+ EXPECT_EQ(18, fragment.size());
EXPECT_EQ(18, std::count(fragment.cbegin(), fragment.cend(), 0));
}
@@ -664,8 +737,9 @@ TEST_F(levin_notify, stem_no_outs_without_padding)
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
+ {
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
-
+ }
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
@@ -1034,7 +1108,9 @@ TEST_F(levin_notify, stem_no_outs_with_padding)
ASSERT_LT(0u, io_service_.poll());
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::fluff));
if (events_.has_stem_txes())
+ {
EXPECT_EQ(txs, events_.take_relayed(cryptonote::relay_method::stem));
+ }
notifier.run_fluff();
ASSERT_LT(0u, io_service_.poll());
@@ -2161,20 +2237,31 @@ TEST_F(levin_notify, command_max_bytes)
add_connection(true);
- std::string bytes(4096, 'h');
+ std::string payload(4096, 'h');
+ epee::byte_slice bytes;
+ {
+ epee::levin::message_writer dest{};
+ dest.buffer.write(epee::to_span(payload));
+ bytes = dest.finalize_notify(ping_command);
+ }
- EXPECT_EQ(1, get_connections().notify(ping_command, epee::strspan<std::uint8_t>(bytes), contexts_.front().get_id()));
+ EXPECT_EQ(1, get_connections().send(bytes.clone(), contexts_.front().get_id()));
EXPECT_EQ(1u, contexts_.front().process_send_queue(true));
EXPECT_EQ(1u, receiver_.notified_size());
const received_message msg = receiver_.get_raw_notification();
EXPECT_EQ(ping_command, msg.command);
EXPECT_EQ(contexts_.front().get_id(), msg.connection);
- EXPECT_EQ(bytes, msg.payload);
+ EXPECT_EQ(payload, msg.payload);
- bytes.push_back('e');
+ {
+ payload.push_back('h');
+ epee::levin::message_writer dest{};
+ dest.buffer.write(epee::to_span(payload));
+ bytes = dest.finalize_notify(ping_command);
+ }
- EXPECT_EQ(1, get_connections().notify(ping_command, epee::strspan<std::uint8_t>(bytes), contexts_.front().get_id()));
+ EXPECT_EQ(1, get_connections().send(std::move(bytes), contexts_.front().get_id()));
EXPECT_EQ(1u, contexts_.front().process_send_queue(false));
EXPECT_EQ(0u, receiver_.notified_size());
}
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index dffda5e4e..2836fd948 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -1351,7 +1351,7 @@ TEST(dandelionpp_map, dropped_connection)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(3u, entry.second);
for (const boost::uuids::uuid& connection : in_connections)
@@ -1409,7 +1409,7 @@ TEST(dandelionpp_map, dropped_connection)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(3u, entry.second);
}
{
@@ -1472,7 +1472,7 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(3u, entry.second);
for (const boost::uuids::uuid& connection : in_connections)
@@ -1511,7 +1511,7 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
EXPECT_EQ(2u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(5u, entry.second);
}
// select 3 of 3 connections but do not remap existing links
@@ -1532,7 +1532,7 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
EXPECT_EQ(2u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(5u, entry.second);
}
// map 8 new incoming connections across 3 outgoing links
@@ -1555,7 +1555,7 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(6u, entry.second);
}
}
@@ -1609,7 +1609,7 @@ TEST(dandelionpp_map, dropped_all_connections)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(3u, entry.second);
for (const boost::uuids::uuid& connection : in_connections)
@@ -1641,7 +1641,7 @@ TEST(dandelionpp_map, dropped_all_connections)
}
EXPECT_EQ(3u, used.size());
- for (const std::pair<boost::uuids::uuid, std::size_t>& entry : used)
+ for (const std::pair<const boost::uuids::uuid, std::size_t>& entry : used)
EXPECT_EQ(3u, entry.second);
}
}
diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp
index 4d6f09e69..8d5c784eb 100644
--- a/tests/unit_tests/node_server.cpp
+++ b/tests/unit_tests/node_server.cpp
@@ -250,7 +250,6 @@ TEST(ban, subnet)
TEST(ban, ignores_port)
{
- time_t seconds;
test_core pr_core;
cryptonote::t_cryptonote_protocol_handler<test_core> cprotocol(pr_core, NULL);
Server server(cprotocol);
@@ -294,6 +293,18 @@ TEST(node_server, bind_same_p2p_port)
boost::program_options::variables_map vm;
boost::program_options::store(boost::program_options::parse_command_line(1, argv, desc_options), vm);
+ /*
+ Reason for choosing '127.0.0.2' as the IP:
+
+ A TCP local socket address that has been bound is unavailable for some time after closing, unless the SO_REUSEADDR flag has been set.
+ That's why connections with automatically assigned source port 48080/58080 from previous test blocks the next to bind acceptor
+ so solution is to either set reuse_addr option for each socket in all tests
+ or use ip different from localhost for acceptors in order to not interfere with automatically assigned source endpoints
+
+ Relevant part about REUSEADDR from man:
+ https://www.man7.org/linux/man-pages/man7/ip.7.html
+ */
+ vm.find(nodetool::arg_p2p_bind_ip.name)->second = boost::program_options::variable_value(std::string("127.0.0.2"), false);
vm.find(nodetool::arg_p2p_bind_port.name)->second = boost::program_options::variable_value(std::string(port), false);
boost::program_options::notify(vm);
@@ -311,5 +322,597 @@ TEST(node_server, bind_same_p2p_port)
EXPECT_TRUE(init(new_node(), port_another));
}
+TEST(cryptonote_protocol_handler, race_condition)
+{
+ struct contexts {
+ using basic = epee::net_utils::connection_context_base;
+ using cryptonote = cryptonote::cryptonote_connection_context;
+ using p2p = nodetool::p2p_connection_context_t<cryptonote>;
+ };
+ using context_t = contexts::p2p;
+ using handler_t = epee::levin::async_protocol_handler<context_t>;
+ using connection_t = epee::net_utils::connection<handler_t>;
+ using connection_ptr = boost::shared_ptr<connection_t>;
+ using connections_t = std::vector<connection_ptr>;
+ using shared_state_t = typename connection_t::shared_state;
+ using shared_state_ptr = std::shared_ptr<shared_state_t>;
+ using io_context_t = boost::asio::io_service;
+ using event_t = epee::simple_event;
+ using ec_t = boost::system::error_code;
+ auto create_conn_pair = [](connection_ptr in, connection_ptr out) {
+ using endpoint_t = boost::asio::ip::tcp::endpoint;
+ using acceptor_t = boost::asio::ip::tcp::acceptor;
+ io_context_t io_context;
+ endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262);
+ acceptor_t acceptor(io_context);
+ ec_t ec;
+ acceptor.open(endpoint.protocol(), ec);
+ EXPECT_EQ(ec.value(), 0);
+ acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor.bind(endpoint, ec);
+ EXPECT_EQ(ec.value(), 0);
+ acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
+ EXPECT_EQ(ec.value(), 0);
+ out->socket().open(endpoint.protocol(), ec);
+ EXPECT_EQ(ec.value(), 0);
+ acceptor.async_accept(in->socket(), [](const ec_t &ec){});
+ out->socket().async_connect(endpoint, [](const ec_t &ec){});
+ io_context.run();
+ acceptor.close(ec);
+ EXPECT_EQ(ec.value(), 0);
+ EXPECT_TRUE(in->start(true, true));
+ EXPECT_TRUE(out->start(false, true));
+ return std::make_pair<>(std::move(in), std::move(out));
+ };
+ auto get_conn_tag = [](connection_t &conn){
+ context_t context;
+ conn.get_context(context);
+ return context.m_connection_id;
+ };
+ using work_t = boost::asio::io_service::work;
+ using work_ptr = std::shared_ptr<work_t>;
+ using workers_t = std::vector<std::thread>;
+ using commands_handler_t = epee::levin::levin_commands_handler<context_t>;
+ using p2p_endpoint_t = nodetool::i_p2p_endpoint<contexts::cryptonote>;
+ using core_t = cryptonote::core;
+ using core_ptr = std::unique_ptr<core_t>;
+ using core_protocol_t = cryptonote::t_cryptonote_protocol_handler<core_t>;
+ using core_protocol_ptr = std::shared_ptr<core_protocol_t>;
+ using block_t = cryptonote::block;
+ using diff_t = cryptonote::difficulty_type;
+ using reward_t = uint64_t;
+ using height_t = uint64_t;
+ struct span {
+ using blocks = epee::span<const block_t>;
+ };
+ auto get_block_template = [](
+ core_t &core,
+ block_t &block,
+ diff_t &diff,
+ reward_t &reward
+ ){
+ auto &storage = core.get_blockchain_storage();
+ const auto height = storage.get_current_blockchain_height();
+ const auto hardfork = storage.get_current_hard_fork_version();
+ block.major_version = hardfork;
+ block.minor_version = storage.get_ideal_hard_fork_version();
+ block.prev_id = storage.get_tail_id();
+ auto &db = storage.get_db();
+ block.timestamp = db.get_top_block_timestamp();
+ block.nonce = 0xACAB;
+ block.miner_tx.vin.clear();
+ block.miner_tx.vout.clear();
+ block.miner_tx.extra.clear();
+ block.miner_tx.version = hardfork >= 4 ? 2 : 1;
+ block.miner_tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
+ block.miner_tx.vin.push_back(cryptonote::txin_gen{height});
+ cryptonote::add_tx_pub_key_to_extra(block.miner_tx, {});
+ cryptonote::get_block_reward(
+ db.get_block_weight(height - 1),
+ {},
+ db.get_block_already_generated_coins(height - 1),
+ reward,
+ hardfork
+ );
+ block.miner_tx.vout.push_back(cryptonote::tx_out{reward, cryptonote::txout_to_key{}});
+ diff = storage.get_difficulty_for_next_block();
+ };
+ struct stat {
+ struct chain {
+ diff_t diff;
+ reward_t reward;
+ };
+ };
+ auto add_block = [](
+ core_t &core,
+ const block_t &block,
+ const stat::chain &stat
+ ){
+ core.get_blockchain_storage().get_db().batch_start({}, {});
+ core.get_blockchain_storage().get_db().add_block(
+ {block, cryptonote::block_to_blob(block)},
+ cryptonote::get_transaction_weight(block.miner_tx),
+ core.get_blockchain_storage().get_next_long_term_block_weight(
+ cryptonote::get_transaction_weight(block.miner_tx)
+ ),
+ stat.diff,
+ stat.reward,
+ {}
+ );
+ core.get_blockchain_storage().get_db().batch_stop();
+ };
+ struct messages {
+ struct core {
+ using sync = cryptonote::CORE_SYNC_DATA;
+ };
+ using handshake = nodetool::COMMAND_HANDSHAKE_T<core::sync>;
+ };
+ struct net_node_t: commands_handler_t, p2p_endpoint_t {
+ using span_t = epee::span<const uint8_t>;
+ using string_t = std::string;
+ using zone_t = epee::net_utils::zone;
+ using uuid_t = boost::uuids::uuid;
+ using relay_t = cryptonote::relay_method;
+ using blobs_t = std::vector<cryptonote::blobdata>;
+ using id_t = nodetool::peerid_type;
+ using callback_t = std::function<bool(contexts::cryptonote &, id_t, uint32_t)>;
+ using address_t = epee::net_utils::network_address;
+ using connections_t = std::vector<std::pair<zone_t, uuid_t>>;
+ struct bans {
+ using subnets = std::map<epee::net_utils::ipv4_network_subnet, time_t>;
+ using hosts = std::map<std::string, time_t>;
+ };
+ struct slice {
+ using bytes = epee::byte_slice;
+ };
+ shared_state_ptr shared_state;
+ core_protocol_ptr core_protocol;
+ virtual int invoke(int command, const span_t in, slice::bytes &out, context_t &context) override {
+ if (core_protocol) {
+ if (command == messages::handshake::ID) {
+ return epee::net_utils::buff_to_t_adapter<void, typename messages::handshake::request, typename messages::handshake::response>(
+ command,
+ in,
+ out,
+ [this](int command, typename messages::handshake::request &in, typename messages::handshake::response &out, context_t &context){
+ core_protocol->process_payload_sync_data(in.payload_data, context, true);
+ core_protocol->get_payload_sync_data(out.payload_data);
+ return 1;
+ },
+ context
+ );
+ }
+ bool handled;
+ return core_protocol->handle_invoke_map(false, command, in, out, context, handled);
+ }
+ else
+ return {};
+ }
+ virtual int notify(int command, const span_t in, context_t &context) override {
+ if (core_protocol) {
+ bool handled;
+ slice::bytes out;
+ return core_protocol->handle_invoke_map(true, command, in, out, context, handled);
+ }
+ else
+ return {};
+ }
+ virtual void callback(context_t &context) override {
+ if (core_protocol)
+ core_protocol->on_callback(context);
+ }
+ virtual void on_connection_new(context_t&) override {}
+ virtual void on_connection_close(context_t &context) override {
+ if (core_protocol)
+ core_protocol->on_connection_close(context);
+ }
+ virtual ~net_node_t() override {}
+ virtual bool add_host_fail(const address_t&, unsigned int = {}) override {
+ return {};
+ }
+ virtual bool block_host(address_t address, time_t = {}, bool = {}) override {
+ return {};
+ }
+ virtual bool drop_connection(const contexts::basic& context) override {
+ if (shared_state)
+ return shared_state->close(context.m_connection_id);
+ else
+ return {};
+ }
+ virtual bool for_connection(const uuid_t& uuid, callback_t f) override {
+ if (shared_state)
+ return shared_state->for_connection(uuid,[&f](context_t &context){
+ return f(context, context.peer_id, context.support_flags);
+ });
+ else
+ return {};
+ }
+ virtual bool invoke_command_to_peer(int command, const span_t in, string_t& out, const contexts::basic& context) override {
+ if (shared_state)
+ return shared_state->invoke(command, in, out, context.m_connection_id);
+ else
+ return {};
+ }
+ virtual bool invoke_notify_to_peer(int command, const span_t in, const contexts::basic& context) override {
+ if (shared_state)
+ return shared_state->notify(command, in, context.m_connection_id);
+ else
+ return {};
+ }
+ virtual bool relay_notify_to_list(int command, const span_t in, connections_t connections) override {
+ if (shared_state) {
+ for (auto &e: connections)
+ shared_state->notify(command, in, e.second);
+ }
+ return {};
+ }
+ virtual bool unblock_host(const address_t&) override {
+ return {};
+ }
+ virtual zone_t send_txs(blobs_t, const zone_t, const uuid_t&, relay_t) override {
+ return {};
+ }
+ virtual bans::subnets get_blocked_subnets() override {
+ return {};
+ }
+ virtual bans::hosts get_blocked_hosts() override {
+ return {};
+ }
+ virtual uint64_t get_public_connections_count() override {
+ if (shared_state)
+ return shared_state->get_connections_count();
+ else
+ return {};
+ }
+ virtual void add_used_stripe_peer(const contexts::cryptonote&) override {}
+ virtual void clear_used_stripe_peers() override {}
+ virtual void remove_used_stripe_peer(const contexts::cryptonote&) override {}
+ virtual void for_each_connection(callback_t f) override {
+ if (shared_state)
+ shared_state->foreach_connection([&f](context_t &context){
+ return f(context, context.peer_id, context.support_flags);
+ });
+ }
+ virtual void request_callback(const contexts::basic &context) override {
+ if (shared_state)
+ shared_state->request_callback(context.m_connection_id);
+ }
+ };
+ auto conduct_handshake = [get_conn_tag](net_node_t &net_node, connection_ptr conn){
+ event_t handshaked;
+ net_node.shared_state->for_connection(
+ get_conn_tag(*conn),
+ [&handshaked, &net_node](context_t &context){
+ typename messages::handshake::request msg;
+ net_node.core_protocol->get_payload_sync_data(msg.payload_data);
+ epee::net_utils::async_invoke_remote_command2<typename messages::handshake::response>(
+ context,
+ messages::handshake::ID,
+ msg,
+ *net_node.shared_state,
+ [&handshaked, &net_node](int code, const typename messages::handshake::response &msg, context_t &context){
+ EXPECT_TRUE(code >= 0);
+ net_node.core_protocol->process_payload_sync_data(msg.payload_data, context, true);
+ handshaked.raise();
+ },
+ P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
+ );
+ return true;
+ }
+ );
+ handshaked.wait();
+ };
+ using path_t = boost::filesystem::path;
+ auto create_dir = []{
+ ec_t ec;
+ path_t path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("daemon-%%%%%%%%%%%%%%%%", ec);
+ if (ec)
+ return path_t{};
+ auto success = boost::filesystem::create_directory(path, ec);
+ if (not ec && success)
+ return path;
+ return path_t{};
+ };
+ auto remove_tree = [](const path_t &path){
+ ec_t ec;
+ boost::filesystem::remove_all(path, ec);
+ };
+ using options_t = boost::program_options::variables_map;
+ struct daemon_t {
+ options_t options;
+ core_ptr core;
+ core_protocol_ptr core_protocol;
+ net_node_t net_node;
+ shared_state_ptr shared_state;
+ connections_t conn;
+ };
+ struct daemons_t {
+ daemon_t main;
+ daemon_t alt;
+ };
+ using options_description_t = boost::program_options::options_description;
+
+ const auto dir = create_dir();
+ ASSERT_TRUE(not dir.empty());
+
+ daemons_t daemon{
+ {
+ [&dir]{
+ options_t options;
+ boost::program_options::store(
+ boost::program_options::command_line_parser({
+ "--data-dir",
+ (dir / "main").string(),
+ "--disable-dns-checkpoints",
+ "--check-updates=disabled",
+ "--fixed-difficulty=1",
+ "--block-sync-size=1",
+ "--db-sync-mode=fastest:async:50000",
+ }).options([]{
+ options_description_t options_description{};
+ cryptonote::core::init_options(options_description);
+ return options_description;
+ }()).run(),
+ options
+ );
+ return options;
+ }(),
+ {},
+ {},
+ {},
+ {},
+ {},
+ },
+ {
+ [&dir]{
+ options_t options;
+ boost::program_options::store(
+ boost::program_options::command_line_parser({
+ "--data-dir",
+ (dir / "alt").string(),
+ "--disable-dns-checkpoints",
+ "--check-updates=disabled",
+ "--fixed-difficulty=1",
+ "--block-sync-size=1",
+ "--db-sync-mode=fastest:async:50000",
+ }).options([]{
+ options_description_t options_description{};
+ cryptonote::core::init_options(options_description);
+ return options_description;
+ }()).run(),
+ options
+ );
+ return options;
+ }(),
+ {},
+ {},
+ {},
+ {},
+ {},
+ },
+ };
+
+ io_context_t io_context;
+ work_ptr work = std::make_shared<work_t>(io_context);
+ workers_t workers;
+ while (workers.size() < 4) {
+ workers.emplace_back([&io_context]{
+ io_context.run();
+ });
+ }
+
+ connection_t::set_rate_up_limit(std::numeric_limits<int64_t>::max());
+ connection_t::set_rate_down_limit(std::numeric_limits<int64_t>::max());
+
+ {
+ daemon.main.core = core_ptr(new core_t(nullptr));
+ daemon.main.core->init(daemon.main.options, nullptr, nullptr);
+ daemon.main.net_node.core_protocol = daemon.main.core_protocol = core_protocol_ptr(new core_protocol_t(
+ *daemon.main.core, &daemon.main.net_node, {}
+ ));
+ daemon.main.core->set_cryptonote_protocol(daemon.main.core_protocol.get());
+ daemon.main.core_protocol->init(daemon.main.options);
+ daemon.main.net_node.shared_state = daemon.main.shared_state = std::make_shared<shared_state_t>();
+ daemon.main.shared_state->set_handler(&daemon.main.net_node);
+ daemon.alt.shared_state = std::make_shared<shared_state_t>();
+ daemon.alt.shared_state->set_handler(&daemon.alt.net_node);
+
+ struct {
+ event_t prepare;
+ event_t check;
+ event_t finish;
+ } events;
+ auto connections = create_conn_pair(
+ connection_ptr(new connection_t(io_context, daemon.main.shared_state, {}, {})),
+ connection_ptr(new connection_t(io_context, daemon.alt.shared_state, {}, {}))
+ );
+ {
+ auto conn = connections.first;
+ auto shared_state = daemon.main.shared_state;
+ const auto tag = get_conn_tag(*conn);
+ conn->strand_.post([tag, conn, shared_state, &events]{
+ shared_state->for_connection(tag, [](context_t &context){
+ context.m_expect_height = -1;
+ context.m_expect_response = -1;
+ context.m_last_request_time = boost::date_time::min_date_time;
+ context.m_score = 0;
+ context.m_state = contexts::cryptonote::state_synchronizing;
+ return true;
+ });
+ events.prepare.raise();
+ events.check.wait();
+ shared_state->for_connection(tag, [](context_t &context){
+ EXPECT_TRUE(context.m_expect_height == -1);
+ EXPECT_TRUE(context.m_expect_response == -1);
+ EXPECT_TRUE(context.m_last_request_time == boost::date_time::min_date_time);
+ EXPECT_TRUE(context.m_score == 0);
+ EXPECT_TRUE(context.m_state == contexts::cryptonote::state_synchronizing);
+ return true;
+ });
+ events.finish.raise();
+ });
+ }
+ events.prepare.wait();
+ daemon.main.core_protocol->on_idle();
+ events.check.raise();
+ events.finish.wait();
+
+ connections.first->strand_.post([connections]{
+ connections.first->cancel();
+ });
+ connections.second->strand_.post([connections]{
+ connections.second->cancel();
+ });
+ connections.first.reset();
+ connections.second.reset();
+ while (daemon.main.shared_state->sock_count);
+ while (daemon.alt.shared_state->sock_count);
+ daemon.main.core_protocol->deinit();
+ daemon.main.core->stop();
+ daemon.main.core->deinit();
+ daemon.main.net_node.shared_state.reset();
+ daemon.main.shared_state.reset();
+ daemon.main.core_protocol.reset();
+ daemon.main.core.reset();
+ daemon.alt.shared_state.reset();
+ }
+
+ {
+ daemon.main.core = core_ptr(new core_t(nullptr));
+ daemon.main.core->init(daemon.main.options, nullptr, nullptr);
+ daemon.main.net_node.core_protocol = daemon.main.core_protocol = core_protocol_ptr(new core_protocol_t(
+ *daemon.main.core, &daemon.main.net_node, {}
+ ));
+ daemon.main.core->set_cryptonote_protocol(daemon.main.core_protocol.get());
+ daemon.main.core->set_checkpoints({});
+ daemon.main.core_protocol->init(daemon.main.options);
+ daemon.main.net_node.shared_state = daemon.main.shared_state = std::make_shared<shared_state_t>();
+ daemon.main.shared_state->set_handler(&daemon.main.net_node);
+ daemon.alt.core = core_ptr(new core_t(nullptr));
+ daemon.alt.core->init(daemon.alt.options, nullptr, nullptr);
+ daemon.alt.net_node.core_protocol = daemon.alt.core_protocol = core_protocol_ptr(new core_protocol_t(
+ *daemon.alt.core, &daemon.alt.net_node, {}
+ ));
+ daemon.alt.core->set_cryptonote_protocol(daemon.alt.core_protocol.get());
+ daemon.alt.core->set_checkpoints({});
+ daemon.alt.core_protocol->init(daemon.alt.options);
+ daemon.alt.net_node.shared_state = daemon.alt.shared_state = std::make_shared<shared_state_t>();
+ daemon.alt.shared_state->set_handler(&daemon.alt.net_node);
+
+ struct {
+ io_context_t io_context;
+ work_ptr work;
+ workers_t workers;
+ } check;
+ check.work = std::make_shared<work_t>(check.io_context);
+ check.workers.emplace_back([&check]{
+ check.io_context.run();
+ });
+ while (daemon.main.conn.size() < 1) {
+ daemon.main.conn.emplace_back(new connection_t(check.io_context, daemon.main.shared_state, {}, {}));
+ daemon.alt.conn.emplace_back(new connection_t(io_context, daemon.alt.shared_state, {}, {}));
+ create_conn_pair(daemon.main.conn.back(), daemon.alt.conn.back());
+ conduct_handshake(daemon.alt.net_node, daemon.alt.conn.back());
+ }
+ struct {
+ event_t prepare;
+ event_t sync;
+ event_t finish;
+ } events;
+ {
+ auto conn = daemon.main.conn.back();
+ auto shared_state = daemon.main.shared_state;
+ const auto tag = get_conn_tag(*conn);
+ conn->strand_.post([tag, conn, shared_state, &events]{
+ shared_state->for_connection(tag, [](context_t &context){
+ EXPECT_TRUE(context.m_state == contexts::cryptonote::state_normal);
+ return true;
+ });
+ events.prepare.raise();
+ events.sync.wait();
+ shared_state->for_connection(tag, [](context_t &context){
+ EXPECT_TRUE(context.m_state == contexts::cryptonote::state_normal);
+ return true;
+ });
+ events.finish.raise();
+ });
+ }
+ events.prepare.wait();
+ daemon.main.core->get_blockchain_storage().add_block_notify(
+ [&events](height_t height, span::blocks blocks){
+ if (height >= CRYPTONOTE_PRUNING_STRIPE_SIZE)
+ events.sync.raise();
+ }
+ );
+ {
+ stat::chain stat{
+ daemon.alt.core->get_blockchain_storage().get_db().get_block_cumulative_difficulty(
+ daemon.alt.core->get_current_blockchain_height() - 1
+ ),
+ daemon.alt.core->get_blockchain_storage().get_db().get_block_already_generated_coins(
+ daemon.alt.core->get_current_blockchain_height() - 1
+ ),
+ };
+ while (daemon.alt.core->get_current_blockchain_height() < CRYPTONOTE_PRUNING_STRIPE_SIZE + CRYPTONOTE_PRUNING_TIP_BLOCKS) {
+ block_t block;
+ diff_t diff;
+ reward_t reward;
+ get_block_template(*daemon.alt.core, block, diff, reward);
+ stat.diff += diff;
+ stat.reward = stat.reward < (MONEY_SUPPLY - stat.reward) ? stat.reward + reward : MONEY_SUPPLY;
+ add_block(*daemon.alt.core, block, stat);
+ if (daemon.main.core->get_current_blockchain_height() + 1 < CRYPTONOTE_PRUNING_STRIPE_SIZE)
+ add_block(*daemon.main.core, block, stat);
+ }
+ }
+ while (daemon.main.conn.size() < 2) {
+ daemon.main.conn.emplace_back(new connection_t(io_context, daemon.main.shared_state, {}, {}));
+ daemon.alt.conn.emplace_back(new connection_t(io_context, daemon.alt.shared_state, {}, {}));
+ create_conn_pair(daemon.main.conn.back(), daemon.alt.conn.back());
+ conduct_handshake(daemon.alt.net_node, daemon.alt.conn.back());
+ }
+ events.finish.wait();
+
+ for (;daemon.main.conn.size(); daemon.main.conn.pop_back()) {
+ auto conn = daemon.main.conn.back();
+ conn->strand_.post([conn]{
+ conn->cancel();
+ });
+ }
+ for (;daemon.alt.conn.size(); daemon.alt.conn.pop_back()) {
+ auto conn = daemon.alt.conn.back();
+ conn->strand_.post([conn]{
+ conn->cancel();
+ });
+ }
+ while (daemon.main.shared_state->sock_count);
+ while (daemon.alt.shared_state->sock_count);
+ daemon.main.core_protocol->deinit();
+ daemon.main.core->stop();
+ daemon.main.core->deinit();
+ daemon.main.net_node.shared_state.reset();
+ daemon.main.shared_state.reset();
+ daemon.main.core_protocol.reset();
+ daemon.main.core.reset();
+ daemon.alt.core_protocol->deinit();
+ daemon.alt.core->stop();
+ daemon.alt.core->deinit();
+ daemon.alt.net_node.shared_state.reset();
+ daemon.alt.shared_state.reset();
+ daemon.alt.core_protocol.reset();
+ daemon.alt.core.reset();
+ check.work.reset();
+ for (auto& w: check.workers) {
+ w.join();
+ }
+ }
+
+ work.reset();
+ for (auto& w: workers) {
+ w.join();
+ }
+ remove_tree(dir);
+}
+
namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; }
namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; }
diff --git a/tests/unit_tests/output_selection.cpp b/tests/unit_tests/output_selection.cpp
index cff509451..20dc58e03 100644
--- a/tests/unit_tests/output_selection.cpp
+++ b/tests/unit_tests/output_selection.cpp
@@ -206,7 +206,7 @@ TEST(select_outputs, same_distribution)
for (size_t i = 0; i < chain_picks.size(); ++i)
chain_norm[i * 100 / chain_picks.size()] += chain_picks[i];
- double max_dev = 0.0, avg_dev = 0.0;
+ double avg_dev = 0.0;
for (size_t i = 0; i < 100; ++i)
{
const double diff = (double)output_norm[i] - (double)chain_norm[i];
diff --git a/tests/unit_tests/wipeable_string.cpp b/tests/unit_tests/wipeable_string.cpp
index 9911bd6f4..0e0bf8906 100644
--- a/tests/unit_tests/wipeable_string.cpp
+++ b/tests/unit_tests/wipeable_string.cpp
@@ -189,20 +189,20 @@ TEST(wipeable_string, parse_hexstr)
{
boost::optional<epee::wipeable_string> s;
- ASSERT_EQ(boost::none, epee::wipeable_string("x").parse_hexstr());
- ASSERT_EQ(boost::none, epee::wipeable_string("x0000000000000000").parse_hexstr());
- ASSERT_EQ(boost::none, epee::wipeable_string("0000000000000000x").parse_hexstr());
- ASSERT_EQ(boost::none, epee::wipeable_string("0").parse_hexstr());
- ASSERT_EQ(boost::none, epee::wipeable_string("000").parse_hexstr());
+ ASSERT_TRUE(boost::none == epee::wipeable_string("x").parse_hexstr());
+ ASSERT_TRUE(boost::none == epee::wipeable_string("x0000000000000000").parse_hexstr());
+ ASSERT_TRUE(boost::none == epee::wipeable_string("0000000000000000x").parse_hexstr());
+ ASSERT_TRUE(boost::none == epee::wipeable_string("0").parse_hexstr());
+ ASSERT_TRUE(boost::none == epee::wipeable_string("000").parse_hexstr());
ASSERT_TRUE((s = epee::wipeable_string("").parse_hexstr()) != boost::none);
- ASSERT_EQ(*s, "");
+ ASSERT_TRUE(*s == "");
ASSERT_TRUE((s = epee::wipeable_string("00").parse_hexstr()) != boost::none);
- ASSERT_EQ(*s, epee::wipeable_string("", 1));
+ ASSERT_TRUE(*s == epee::wipeable_string("", 1));
ASSERT_TRUE((s = epee::wipeable_string("41").parse_hexstr()) != boost::none);
- ASSERT_EQ(*s, epee::wipeable_string("A"));
+ ASSERT_TRUE(*s == epee::wipeable_string("A"));
ASSERT_TRUE((s = epee::wipeable_string("414243").parse_hexstr()) != boost::none);
- ASSERT_EQ(*s, epee::wipeable_string("ABC"));
+ ASSERT_TRUE(*s == epee::wipeable_string("ABC"));
}
TEST(wipeable_string, to_hex)
diff --git a/tests/unit_tests/zmq_rpc.cpp b/tests/unit_tests/zmq_rpc.cpp
index 59759bed8..66a7f3ac1 100644
--- a/tests/unit_tests/zmq_rpc.cpp
+++ b/tests/unit_tests/zmq_rpc.cpp
@@ -202,7 +202,6 @@ namespace
MASSERT(!expected.empty());
std::size_t actual_height = 0;
- crypto::hash actual_id{};
crypto::hash actual_prev_id{};
std::vector<crypto::hash> actual_ids{};
GET_FROM_JSON_OBJECT(pub.second, actual_height, first_height);