Compare commits

...

39 Commits

Author SHA1 Message Date
luigi1111 f6e63ef260 Merge pull request #7647
d7b74a4 Tests: Fix test node_server.bind_same_p2p_port from randomly crashing (mj-xmr)
2021-04-06 12:25:41 -05:00
luigi1111 298208d92b Merge pull request #7350
4a9ae3e fix serialization being different on mac (moneromooo-monero)
2021-04-06 12:21:28 -05:00
mj-xmr d7b74a4fb0 Tests: Fix test node_server.bind_same_p2p_port from randomly crashing 2021-04-05 17:51:54 +02:00
luigi1111 f719b74cd1 Merge pull request #7638
c18cdd3 build: prepare v0.17.2.0 (selsta)
2021-03-29 22:00:40 -04:00
luigi1111 1d597ad910 Merge pull request #7637
13978a9 depends: openssl 1.1.1i -> 1.1.1k (selsta)
2021-03-29 22:00:06 -04:00
luigi1111 4f6eea9021 Merge pull request #7631
fd869a7 cmake: Don't default to -march=native on OpenBSD (Nathan Dorfman)
2021-03-29 21:58:31 -04:00
luigi1111 076254d113 Merge pull request #7623
c8c7c40 ITS#9500 fix regression from ITS#8662 (Howard Chu)
2021-03-29 21:57:26 -04:00
luigi1111 daa1376370 Merge pull request #7621
21ab1de cryptonote_protocol_handler: fix race condition (anon)
699e82c cryptonote_protocol_handler: add race condition demo (anon)
2021-03-29 21:56:07 -04:00
luigi1111 eed63cef36 Merge pull request #7615
9ca9f12 Fixed issues found by static analysis (SChernykh)
2021-03-29 21:54:25 -04:00
luigi1111 dcdbf7ebcf Merge pull request #7459
d5b78c0 async_protocol_handler_config: fix deadlock (anon) f59b1d5 async_protocol_handler_config: add deadlock demo (anon)
2021-03-29 21:22:54 -04:00
selsta c18cdd3623 build: prepare v0.17.2.0 2021-03-26 01:53:45 +01:00
selsta 13978a9887 depends: openssl 1.1.1i -> 1.1.1k 2021-03-25 21:45:03 +01:00
Nathan Dorfman fd869a7b64 cmake: Don't default to -march=native on OpenBSD 2021-03-24 15:48:56 -06:00
Howard Chu c8c7c40ac8 ITS#9500 fix regression from ITS#8662
mdb_load -a patch broke overwriting with MDB_CURRENT
2021-03-23 21:08:19 +00:00
anon 21ab1de89f cryptonote_protocol_handler: fix race condition 2021-03-22 19:42:45 +00:00
anon 699e82c282 cryptonote_protocol_handler: add race condition demo 2021-03-22 19:42:45 +00:00
luigi1111 9ec4ce36c7 Merge pull request #7419
25588de trezor: simplify recognition of integrated addresses (Dusan Klinec)
2021-03-20 01:54:52 -04:00
SChernykh 9ca9f1214a Fixed issues found by static analysis
- rolling_median: tried to free uninitialized pointer in a constructor
- net_node.inl: erase-remove idiom was used incorrectly. remove_if doesn't actually remove elements, see http://cpp.sh/6fcjv
- bulletproofs.cc: call to sizeof() instead of vector.size(), luckily it only impacts performance and not code logic there
2021-03-18 21:57:13 +01:00
anon d5b78c08b6 async_protocol_handler_config: fix deadlock 2021-03-12 11:59:05 +00:00
anon f59b1d5fb5 async_protocol_handler_config: add deadlock demo 2021-03-12 11:59:05 +00:00
moneromooo-monero 4a9ae3eb8b fix serialization being different on mac
On Mac, size_t is a distinct type from uint64_t, and some
types (in wallet cache as well as cold/hot wallet transfer
data) use pairs/containers with size_t as fields. Mac would
save those as full size, while other platforms would save
them as varints. Might apply to other platforms where the
types are distinct.

There's a nasty hack for backward compatibility, which can
go after a couple forks.
2021-03-05 23:41:19 +00:00
luigi1111 837c9aec22 Merge pull request #7390
7fd140e async_protocol_handler_config: remove connection correctly (anon)
c1776be async_protocol_handler_config: add segfault demo (anon)
2021-03-05 13:56:12 -05:00
luigi1111 af46a291ad Merge pull request #7336
d8137dc device_trezor: add redundant check (anon)
c6e1d7b device_trezor: wipe string fields properly (anon)
2021-03-05 13:53:00 -05:00
Dusan Klinec 25588de40c trezor: simplify recognition of integrated addresses
now it is possible to simplify integrated addresses recognition using transaction destination info directly
fixes https://github.com/monero-project/monero-gui/issues/3346
2021-03-03 15:39:12 +01:00
anon 7fd140e4f7 async_protocol_handler_config: remove connection correctly 2021-02-19 22:27:28 +00:00
anon c1776be54f async_protocol_handler_config: add segfault demo 2021-02-19 22:27:28 +00:00
luigi1111 30bc575505 Merge pull request #7362
332b973 ITS#9007 don't free loose writemap pages (Kris Zyp)
2021-02-18 14:08:58 -05:00
luigi1111 aa408d1c72 Merge pull request #7333
b5667c9 p2p: allow CIDR notation in DNS blocklist (moneromooo-monero)
2021-02-16 11:45:38 -05:00
luigi1111 c8895ccbb7 Merge pull request #7309
6d5e210 boosted_tcp_server: fix connection lifetime (anon)
afec439 boosted_tcp_server: add segfault demo (anon)
2021-02-15 21:56:07 -05:00
luigi1111 975d390d00 Merge pull request #7284
32ab89a docs: Remove outdated bits about anonymity network seed nodes (Nathan Dorfman)
2021-02-15 21:49:50 -05:00
Kris Zyp 332b9734ff ITS#9007 don't free loose writemap pages
Broken in ITS#8756
2021-02-01 16:10:09 +00:00
moneromooo-monero b5667c9f6c p2p: allow CIDR notation in DNS blocklist 2021-01-21 01:41:31 +00:00
anon d8137dc523 device_trezor: add redundant check 2021-01-20 22:07:13 +01:00
anon c6e1d7bcdf device_trezor: wipe string fields properly 2021-01-20 22:07:13 +01:00
anon 6d5e2106b3 boosted_tcp_server: fix connection lifetime 2021-01-19 18:16:01 +01:00
anon afec439953 boosted_tcp_server: add segfault demo 2021-01-19 18:16:01 +01:00
luigi1111 25670398b1 Merge pull request #7295
fe6dda9 p2p: only log to global when a blocked IP is not already blocked (moneromooo-monero)
2021-01-15 23:53:40 -05:00
moneromooo-monero fe6dda9453 p2p: only log to global when a blocked IP is not already blocked 2021-01-08 15:50:10 +00:00
Nathan Dorfman 32ab89aa86 docs: Remove outdated bits about anonymity network seed nodes 2021-01-05 23:05:05 -07:00
31 changed files with 1147 additions and 154 deletions
+3 -6
View File
@@ -36,10 +36,6 @@ with additional exclusive IPv4 address(es).
## Usage
Anonymity networks have no seed nodes (the feature is still considered
experimental), so a user must specify an address. If configured properly,
additional peers can be found through typical p2p peerlist sharing.
### Outbound Connections
Connecting to an anonymous address requires the command line option
@@ -54,8 +50,9 @@ separate process. On most systems the configuration will look like:
which tells `monerod` that ".onion" p2p addresses can be forwarded to a socks
proxy at IP 127.0.0.1 port 9050 with a max of 10 outgoing connections and
".b32.i2p" p2p addresses can be forwarded to a socks proxy at IP 127.0.0.1 port
9000 with the default max outgoing connections. Since there are no seed nodes
for anonymity connections, peers must be manually specified:
9000 with the default max outgoing connections.
If desired, peers can be manually specified:
```
--add-exclusive-node rveahdfho7wo4b2m.onion:28083
+12 -1
View File
@@ -501,6 +501,17 @@ endif()
# Trezor support check
include(CheckTrezor)
# As of OpenBSD 6.8, -march=<anything> breaks the build
function(set_default_arch)
if (OPENBSD)
set(ARCH default)
else()
set(ARCH native)
endif()
set(ARCH ${ARCH} CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
endfunction()
if(MSVC)
add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
@@ -514,7 +525,7 @@ if(MSVC)
else()
include(TestCXXAcceptsFlag)
if (NOT ARCH)
set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
set_default_arch()
endif()
message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}")
if(ARCH STREQUAL "default")
+5 -5
View File
@@ -134,8 +134,8 @@ Dates are provided in the format YYYY-MM-DD.
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.9 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.9 | forbid old MLSAG transaction format
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.2.0 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.2.0 | forbid old MLSAG transaction format
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
@@ -295,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout tags/v0.17.1.9
git checkout tags/v0.17.2.0
```
* Build:
@@ -412,10 +412,10 @@ application.
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.9'. If you don't care about the version and just want binaries from master, skip this step:
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.2.0'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.17.1.9
git checkout v0.17.2.0
```
* If you are on a 64-bit system, run:
+2 -2
View File
@@ -1,8 +1,8 @@
package=openssl
$(package)_version=1.1.1i
$(package)_version=1.1.1k
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
$(package)_sha256_hash=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
@@ -269,8 +269,6 @@ PRAGMA_WARNING_DISABLE_VS(4355)
//_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
CRITICAL_REGION_LOCAL(self->m_self_refs_lock);
//_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
if(m_was_shutdown)
return false;
++m_reference_count;
m_self_ref = std::move(self);
return true;
@@ -800,36 +800,32 @@ void async_protocol_handler_config<t_connection_context>::del_connection(async_p
template<class t_connection_context>
void async_protocol_handler_config<t_connection_context>::delete_connections(size_t count, bool incoming)
{
std::vector <boost::uuids::uuid> connections;
std::vector<typename connections_map::mapped_type> connections;
auto scope_exit_handler = misc_utils::create_scope_leave_handler([&connections]{
for (auto &aph: connections)
aph->finish_outer_call();
});
CRITICAL_REGION_BEGIN(m_connects_lock);
for (auto& c: m_connects)
{
if (c.second->m_connection_context.m_is_income == incoming)
connections.push_back(c.first);
if (c.second->start_outer_call())
connections.push_back(c.second);
}
// close random connections from the provided set
// TODO or better just keep removing random elements (performance)
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
shuffle(connections.begin(), connections.end(), std::default_random_engine(seed));
while (count > 0 && connections.size() > 0)
{
try
{
auto i = connections.end() - 1;
async_protocol_handler<t_connection_context> *conn = m_connects.at(*i);
del_connection(conn);
conn->close();
connections.erase(i);
}
catch (const std::out_of_range &e)
{
MWARNING("Connection not found in m_connects, continuing");
}
--count;
}
for (size_t i = 0; i < connections.size() && i < count; ++i)
m_connects.erase(connections[i]->get_connection_id());
CRITICAL_REGION_END();
for (size_t i = 0; i < connections.size() && i < count; ++i)
connections[i]->close();
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
@@ -891,23 +887,35 @@ int async_protocol_handler_config<t_connection_context>::invoke_async(int comman
template<class t_connection_context> template<class callback_t>
bool async_protocol_handler_config<t_connection_context>::foreach_connection(const callback_t &cb)
{
CRITICAL_REGION_LOCAL(m_connects_lock);
for(auto& c: m_connects)
{
async_protocol_handler<t_connection_context>* aph = c.second;
if(!cb(aph->get_context_ref()))
std::vector<typename connections_map::mapped_type> conn;
auto scope_exit_handler = misc_utils::create_scope_leave_handler([&conn]{
for (auto &aph: conn)
aph->finish_outer_call();
});
CRITICAL_REGION_BEGIN(m_connects_lock);
conn.reserve(m_connects.size());
for (auto &e: m_connects)
if (e.second->start_outer_call())
conn.push_back(e.second);
CRITICAL_REGION_END()
for (auto &aph: conn)
if (!cb(aph->get_context_ref()))
return false;
}
return true;
}
//------------------------------------------------------------------------------------------
template<class t_connection_context> template<class callback_t>
bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb)
{
CRITICAL_REGION_LOCAL(m_connects_lock);
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
if (!aph)
async_protocol_handler<t_connection_context>* aph = nullptr;
if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
return false;
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler<t_connection_context>::finish_outer_call, aph));
if(!cb(aph->get_context_ref()))
return false;
return true;
@@ -970,12 +978,14 @@ int async_protocol_handler_config<t_connection_context>::send(byte_slice message
template<class t_connection_context>
bool async_protocol_handler_config<t_connection_context>::close(boost::uuids::uuid connection_id)
{
CRITICAL_REGION_LOCAL(m_connects_lock);
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
if (!aph)
async_protocol_handler<t_connection_context>* aph = nullptr;
if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
return false;
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler<t_connection_context>::finish_outer_call, aph));
if (!aph->close())
return false;
CRITICAL_REGION_LOCAL(m_connects_lock);
m_connects.erase(connection_id);
return true;
}
-1
View File
@@ -141,7 +141,6 @@ public:
rolling_median_t(rolling_median_t &&m)
{
free(data);
memcpy(this, &m, sizeof(rolling_median_t));
m.data = NULL;
}
+2 -2
View File
@@ -126,7 +126,7 @@ Setup for LXC:
```bash
GH_USER=fluffypony
VERSION=v0.17.1.9
VERSION=v0.17.2.0
./gitian-build.py --setup $GH_USER $VERSION
```
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
```bash
GH_USER=fluffypony
VERSION=v0.17.1.9
VERSION=v0.17.2.0
gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
+2 -2
View File
@@ -3461,9 +3461,9 @@ mdb_freelist_save(MDB_txn *txn)
} else {
x = mdb_mid2l_search(dl, mp->mp_pgno);
mdb_tassert(txn, dl[x].mid == mp->mp_pgno);
mdb_dpage_free(env, mp);
}
dl[x].mptr = NULL;
mdb_dpage_free(env, mp);
}
{
/* squash freed slots out of the dirty list */
@@ -7867,7 +7867,7 @@ put_sub:
xdata.mv_size = 0;
xdata.mv_data = "";
leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
if (flags == MDB_CURRENT) {
if ((flags & (MDB_CURRENT|MDB_APPENDDUP)) == MDB_CURRENT) {
xflags = MDB_CURRENT|MDB_NOSPILL;
} else {
mdb_xcursor_init1(mc, leaf);
Binary file not shown.
+1
View File
@@ -246,6 +246,7 @@ namespace cryptonote
ADD_CHECKPOINT2(2248500, "125d0872f00b54730b1e6f925f9d211b0158dd0e254de8cefa371f2e7aba5118", "0x115c89ab7abec4a");
ADD_CHECKPOINT2(2257500, "99643c32f27b157c6952a67af7dbe07ca819e71df386fa9379a344686d2950cf", "0x11c2f448d4f8830");
ADD_CHECKPOINT2(2265000, "727a6228a71f5b35c899553ee19d60bfc10c126a009ffd633afb30666e8edbe6", "0x121a33e656ecad4");
ADD_CHECKPOINT2(2325000, "f61261994b368700f0cbbfb4477433fa36a3c7537908ab2d1a06ac2987cc8b01", "0x154bceeffaff847");
return true;
}
@@ -77,6 +77,8 @@ namespace cryptonote
int m_expect_response;
uint64_t m_expect_height;
size_t m_num_requested;
epee::copyable_atomic m_new_stripe_notification{0};
epee::copyable_atomic m_idle_peer_notification{0};
};
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
+1 -1
View File
@@ -5390,7 +5390,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "b6fa3343a9465692873bb9cf4d161d1d0316d4e3422fa7a57f6228526e8f5520";
static const char expected_block_hashes_hash[] = "b198c2514bed71ca0a43cba6590090068daf6d207b351d8a4c7d0f0f791c095f";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
+2 -2
View File
@@ -44,10 +44,10 @@ namespace cryptonote
typedef std::pair<uint64_t, rct::ctkey> output_entry;
std::vector<output_entry> outputs; //index + key + optional ringct commitment
size_t real_output; //index in outputs vector of real output_entry
uint64_t real_output; //index in outputs vector of real output_entry
crypto::public_key real_out_tx_key; //incoming real tx public key
std::vector<crypto::public_key> real_out_additional_tx_keys; //incoming real tx additional public keys
size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money
bool rct; //true if the output is rct
rct::key mask; //ringct amount mask
@@ -137,6 +137,41 @@ namespace cryptonote
CHECK_AND_ASSERT_MES_CC( context.m_callback_request_count > 0, false, "false callback fired, but context.m_callback_request_count=" << context.m_callback_request_count);
--context.m_callback_request_count;
uint32_t notified = true;
if (context.m_idle_peer_notification.compare_exchange_strong(notified, not notified))
{
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
{
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
const auto ms = dt.total_microseconds();
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
{
if (context.m_score-- >= 0)
{
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
context.m_last_request_time = boost::date_time::not_a_date_time;
context.m_expect_response = 0;
context.m_expect_height = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
}
else
{
MINFO(context << "dropping idle peer with negative score");
drop_connection_with_score(context, context.m_expect_response == 0 ? 1 : 5, false);
return false;
}
}
}
}
notified = true;
if (context.m_new_stripe_notification.compare_exchange_strong(notified, not notified))
{
if (context.m_state == cryptonote_connection_context::state_normal)
context.m_state = cryptonote_connection_context::state_synchronizing;
}
if(context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time == boost::posix_time::not_a_date_time)
{
NOTIFY_REQUEST_CHAIN::request r = {};
@@ -1688,7 +1723,7 @@ skip:
const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
if (stripe && peer_stripe && peer_stripe != stripe)
return true;
context.m_state = cryptonote_connection_context::state_synchronizing;
context.m_new_stripe_notification = true;
LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count;
m_p2p->request_callback(context);
@@ -1711,7 +1746,6 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
{
MTRACE("Checking for idle peers...");
std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers;
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
{
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
@@ -1721,36 +1755,16 @@ skip:
const auto ms = dt.total_microseconds();
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
{
if (context.m_score-- >= 0)
{
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
LOG_PRINT_CCONTEXT_L2("requesting callback");
context.m_last_request_time = boost::date_time::not_a_date_time;
context.m_expect_response = 0;
context.m_expect_height = 0;
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
++context.m_callback_request_count;
m_p2p->request_callback(context);
}
else
{
idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
}
context.m_idle_peer_notification = true;
LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count;
m_p2p->request_callback(context);
MLOG_PEER_STATE("requesting callback");
}
}
return true;
});
for (const auto &e: idle_peers)
{
const auto &uuid = e.first;
m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
MINFO(ctx << "dropping idle peer with negative score");
drop_connection_with_score(ctx, e.second, false);
return true;
});
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------
+9 -20
View File
@@ -365,15 +365,14 @@ namespace trezor {
void device_trezor_base::device_state_initialize_unsafe()
{
require_connected();
std::string tmp_session_id;
auto initMsg = std::make_shared<messages::management::Initialize>();
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
memwipe(&tmp_session_id[0], tmp_session_id.size());
if (initMsg->has_session_id())
memwipe(&(*initMsg->mutable_session_id())[0], initMsg->mutable_session_id()->size());
});
if(!m_device_session_id.empty()) {
tmp_session_id.assign(m_device_session_id.data(), m_device_session_id.size());
initMsg->set_allocated_session_id(&tmp_session_id);
initMsg->set_allocated_session_id(new std::string(m_device_session_id.data(), m_device_session_id.size()));
}
m_features = this->client_exchange<messages::management::Features>(initMsg);
@@ -382,8 +381,6 @@ namespace trezor {
} else {
m_device_session_id.clear();
}
initMsg->release_session_id();
}
void device_trezor_base::device_state_reset()
@@ -453,18 +450,14 @@ namespace trezor {
pin = m_pin;
}
std::string pin_field;
messages::common::PinMatrixAck m;
if (pin) {
pin_field.assign(pin->data(), pin->size());
m.set_allocated_pin(&pin_field);
m.set_allocated_pin(new std::string(pin->data(), pin->size()));
}
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
m.release_pin();
if (!pin_field.empty()){
memwipe(&pin_field[0], pin_field.size());
}
if (m.has_pin())
memwipe(&(*m.mutable_pin())[0], m.mutable_pin()->size());
});
resp = call_raw(&m);
@@ -499,7 +492,6 @@ namespace trezor {
boost::optional<epee::wipeable_string> passphrase;
TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
std::string passphrase_field;
messages::common::PassphraseAck m;
m.set_on_device(on_device);
if (!on_device) {
@@ -512,16 +504,13 @@ namespace trezor {
}
if (passphrase) {
passphrase_field.assign(passphrase->data(), passphrase->size());
m.set_allocated_passphrase(&passphrase_field);
m.set_allocated_passphrase(new std::string(passphrase->data(), passphrase->size()));
}
}
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
m.release_passphrase();
if (!passphrase_field.empty()){
memwipe(&passphrase_field[0], passphrase_field.size());
}
if (m.has_passphrase())
memwipe(&(m.mutable_passphrase())[0], m.mutable_passphrase()->size());
});
resp = call_raw(&m);
+1 -1
View File
@@ -165,7 +165,7 @@ namespace trezor {
// Scoped session closer
BOOST_SCOPE_EXIT_ALL(&, this) {
if (open_session){
if (open_session && this->get_transport()){
this->get_transport()->close();
}
};
+1 -14
View File
@@ -502,21 +502,9 @@ namespace tx {
}
void Signer::compute_integrated_indices(TsxData * tsx_data){
if (m_aux_data == nullptr || m_aux_data->tx_recipients.empty()){
return;
}
auto & chg = tsx_data->change_dts();
std::string change_hash = hash_addr(&chg.addr(), chg.amount(), chg.is_subaddress());
std::vector<uint32_t> integrated_indices;
std::set<std::string> integrated_hashes;
for (auto & cur : m_aux_data->tx_recipients){
if (!cur.has_payment_id){
continue;
}
integrated_hashes.emplace(hash_addr(&cur.address.m_spend_public_key, &cur.address.m_view_public_key));
}
ssize_t idx = -1;
for (auto & cur : tsx_data->outputs()){
@@ -527,8 +515,7 @@ namespace tx {
continue;
}
c_hash = hash_addr(&cur.addr());
if (integrated_hashes.find(c_hash) != integrated_hashes.end()){
if (cur.is_integrated()){
integrated_indices.push_back((uint32_t)idx);
}
}
+27 -11
View File
@@ -234,6 +234,7 @@ namespace nodetool
return false;
const time_t now = time(nullptr);
bool added = false;
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
time_t limit;
@@ -244,7 +245,10 @@ namespace nodetool
const std::string host_str = addr.host_str();
auto it = m_blocked_hosts.find(host_str);
if (it == m_blocked_hosts.end())
{
m_blocked_hosts[host_str] = limit;
added = true;
}
else if (it->second < limit || !add_only)
it->second = limit;
@@ -275,7 +279,10 @@ namespace nodetool
conns.clear();
}
MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
if (added)
MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
else
MINFO("Host " << host_str << " block time updated.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -2020,15 +2027,24 @@ namespace nodetool
boost::split(ips, record, boost::is_any_of(";"));
for (const auto &ip: ips)
{
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(ip, 0);
if (!parsed_addr)
if (ip.empty())
continue;
auto subnet = net::get_ipv4_subnet_address(ip);
if (subnet)
{
MWARNING("Invalid IP address from DNS blocklist: " << ip << " - " << parsed_addr.error());
++bad;
block_subnet(*subnet, DNS_BLOCKLIST_LIFETIME);
++good;
continue;
}
block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true);
++good;
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(ip, 0);
if (parsed_addr)
{
block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true);
++good;
continue;
}
MWARNING("Invalid IP address or subnet from DNS blocklist: " << ip << " - " << parsed_addr.error());
++bad;
}
}
if (good > 0)
@@ -2903,8 +2919,8 @@ namespace nodetool
const uint32_t index = stripe - 1;
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
MINFO("adding stripe " << stripe << " peer: " << context.m_remote_address.str());
std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
m_used_stripe_peers[index].push_back(context.m_remote_address);
}
@@ -2917,8 +2933,8 @@ namespace nodetool
const uint32_t index = stripe - 1;
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
MINFO("removing stripe " << stripe << " peer: " << context.m_remote_address.str());
std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
}
template<class t_payload_net_handler>
+1 -1
View File
@@ -826,7 +826,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
proof_data.reserve(proofs.size());
size_t inv_offset = 0;
std::vector<rct::key> to_invert;
to_invert.reserve(11 * sizeof(proofs));
to_invert.reserve(11 * proofs.size());
size_t max_logM = 0;
for (const Bulletproof *p: proofs)
{
+8 -1
View File
@@ -98,7 +98,7 @@ template <>
struct binary_archive<false> : public binary_archive_base<std::istream, false>
{
explicit binary_archive(stream_type &s) : base_type(s) {
explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) {
stream_type::pos_type pos = stream_.tellg();
stream_.seekg(0, std::ios_base::end);
eof_pos_ = stream_.tellg();
@@ -173,8 +173,13 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false>
assert(stream_.tellg() <= eof_pos_);
return eof_pos_ - stream_.tellg();
}
void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; }
bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; }
protected:
std::streamoff eof_pos_;
bool varint_bug_backward_compatibility_;
};
template <>
@@ -227,6 +232,8 @@ struct binary_archive<true> : public binary_archive_base<std::ostream, true>
void write_variant_tag(variant_tag_type t) {
serialize_int(t);
}
bool varint_bug_backward_compatibility_enabled() const { return false; }
};
POP_WARNINGS
+14 -9
View File
@@ -32,22 +32,27 @@ namespace serialization
{
namespace detail
{
template<typename T>
inline constexpr bool use_container_varint() noexcept
{
return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1;
}
template <typename Archive, class T>
bool serialize_container_element(Archive& ar, T& e)
typename std::enable_if<!use_container_varint<T>(), bool>::type
serialize_container_element(Archive& ar, T& e)
{
return ::do_serialize(ar, e);
}
template <typename Archive>
bool serialize_container_element(Archive& ar, uint32_t& e)
template<typename Archive, typename T>
typename std::enable_if<use_container_varint<T>(), bool>::type
serialize_container_element(Archive& ar, T& e)
{
ar.serialize_varint(e);
return true;
}
static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>();
template <typename Archive>
bool serialize_container_element(Archive& ar, uint64_t& e)
{
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
return ::do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}
+2
View File
@@ -84,6 +84,8 @@ struct json_archive_base
void end_variant() { end_object(); }
Stream &stream() { return stream_; }
bool varint_bug_backward_compatibility_enabled() const { return false; }
protected:
void make_indent()
{
+16 -3
View File
@@ -30,21 +30,34 @@
#pragma once
#include <memory>
#include <boost/type_traits/make_unsigned.hpp>
#include "serialization.h"
namespace serialization
{
namespace detail
{
template<typename T>
inline constexpr bool use_pair_varint() noexcept
{
return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1;
}
template <typename Archive, class T>
bool serialize_pair_element(Archive& ar, T& e)
typename std::enable_if<!use_pair_varint<T>(), bool>::type
serialize_pair_element(Archive& ar, T& e)
{
return ::do_serialize(ar, e);
}
template <typename Archive>
bool serialize_pair_element(Archive& ar, uint64_t& e)
template<typename Archive, typename T>
typename std::enable_if<use_pair_varint<T>(), bool>::type
serialize_pair_element(Archive& ar, T& e)
{
static constexpr const bool previously_varint = std::is_same<uint64_t, T>();
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
return ::do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.17.1.9"
#define DEF_MONERO_VERSION "0.17.2.0"
#define DEF_MONERO_RELEASE_NAME "Oxygen Orion"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
+15 -5
View File
@@ -5649,6 +5649,16 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
if (::serialization::serialize(ar, *this))
if (::serialization::check_stream_state(ar))
loaded = true;
if (!loaded)
{
std::stringstream iss;
iss << cache_data;
binary_archive<false> ar(iss);
ar.enable_varint_bug_backward_compatibility();
if (::serialization::serialize(ar, *this))
if (::serialization::check_stream_state(ar))
loaded = true;
}
}
catch(...) { }
@@ -12439,7 +12449,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
bool wallet2::export_key_images(const std::string &filename, bool all) const
{
PERF_TIMER(export_key_images);
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all);
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all);
std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
const uint32_t offset = ski.first;
@@ -12466,7 +12476,7 @@ bool wallet2::export_key_images(const std::string &filename, bool all) const
}
//----------------------------------------------------------------------------------------------------
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
{
PERF_TIMER(export_key_images_raw);
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
@@ -12963,7 +12973,7 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect
m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
}
//----------------------------------------------------------------------------------------------------
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const
{
PERF_TIMER(export_outputs);
std::vector<tools::wallet2::transfer_details> outs;
@@ -13003,7 +13013,7 @@ std::string wallet2::export_outputs_to_str(bool all) const
return magic + ciphertext;
}
//----------------------------------------------------------------------------------------------------
size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs)
size_t wallet2::import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs)
{
PERF_TIMER(import_outputs);
@@ -13109,7 +13119,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st)
try
{
std::string body(data, headerlen);
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs;
try
{
std::stringstream iss;
+5 -5
View File
@@ -327,7 +327,7 @@ private:
uint64_t m_block_height;
cryptonote::transaction_prefix m_tx;
crypto::hash m_txid;
size_t m_internal_output_index;
uint64_t m_internal_output_index;
uint64_t m_global_output_index;
bool m_spent;
bool m_frozen;
@@ -338,7 +338,7 @@ private:
bool m_rct;
bool m_key_image_known;
bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
size_t m_pk_index;
uint64_t m_pk_index;
cryptonote::subaddress_index m_subaddr_index;
bool m_key_image_partial;
std::vector<rct::key> m_multisig_k;
@@ -1367,9 +1367,9 @@ private:
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
// Import/Export wallet data
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const;
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const;
std::string export_outputs_to_str(bool all = false) const;
size_t import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs);
size_t import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs);
size_t import_outputs_from_str(const std::string &outputs_st);
payment_container export_payments() const;
void import_payments(const payment_container &payments);
@@ -1377,7 +1377,7 @@ private:
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
bool export_key_images(const std::string &filename, bool all = false) const;
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
bool import_key_images(std::vector<crypto::key_image> key_images, size_t offset=0, boost::optional<std::unordered_set<size_t>> selected_transfers=boost::none);
+1 -1
View File
@@ -2702,7 +2702,7 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
res.offset = ski.first;
res.signed_key_images.resize(ski.second.size());
for (size_t n = 0; n < ski.second.size(); ++n)
+1 -1
View File
@@ -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);
@@ -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>, std::string&, 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, {}, 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();
}
+601
View File
@@ -294,6 +294,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 +323,594 @@ 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>;
};
shared_state_ptr shared_state;
core_protocol_ptr core_protocol;
virtual int invoke(int command, const span_t in, string_t &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;
string_t 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>; }