Monero
Loading...
Searching...
No Matches
cryptonote_protocol_handler.inl
Go to the documentation of this file.
1
4
5// Copyright (c) 2014-2022, The Monero Project
6//
7// All rights reserved.
8//
9// Redistribution and use in source and binary forms, with or without modification, are
10// permitted provided that the following conditions are met:
11//
12// 1. Redistributions of source code must retain the above copyright notice, this list of
13// conditions and the following disclaimer.
14//
15// 2. Redistributions in binary form must reproduce the above copyright notice, this list
16// of conditions and the following disclaimer in the documentation and/or other
17// materials provided with the distribution.
18//
19// 3. Neither the name of the copyright holder nor the names of its contributors may be
20// used to endorse or promote products derived from this software without specific
21// prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
24// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
34
35// (may contain code and/or modifications by other developers)
36// developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting
37
38#include <boost/optional/optional.hpp>
39#include <list>
40#include <ctime>
41
43#include "profile_tools.h"
45#include "common/pruning.h"
46#include "common/util.h"
47#include "misc_log_ex.h"
48
49#undef MONERO_DEFAULT_LOG_CATEGORY
50#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
51
52#define MLOG_P2P_MESSAGE(x) MCINFO("net.p2p.msg", context << x)
53#define MLOGIF_P2P_MESSAGE(init, test, x) \
54 do { \
55 const auto level = el::Level::Info; \
56 const char *cat = "net.p2p.msg"; \
57 if (ELPP->vRegistry()->allowed(level, cat)) { \
58 init; \
59 if (test) { \
60 LOG_TO_STRING(x); \
61 el::base::Writer(level, el::Color::Default, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::NormalLog).construct(cat) << str; \
62 } \
63 } \
64 } while(0)
65
66#define MLOG_PEER_STATE(x) \
67 MCINFO(MONERO_DEFAULT_LOG_CATEGORY, context << "[" << epee::string_tools::to_string_hex(context.m_pruning_seed) << "] state: " << x << " in state " << cryptonote::get_protocol_state_string(context.m_state))
68
69#define BLOCK_QUEUE_NSPANS_THRESHOLD 10 // chunks of N blocks
70#define BLOCK_QUEUE_SIZE_THRESHOLD (100*1024*1024) // MB
71#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS 1000
72#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY (5 * 1000000) // microseconds
73#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD (30 * 1000000) // microseconds
74#define IDLE_PEER_KICK_TIME (240 * 1000000) // microseconds
75#define NON_RESPONSIVE_PEER_KICK_TIME (20 * 1000000) // microseconds
76#define PASSIVE_PEER_KICK_TIME (60 * 1000000) // microseconds
77#define DROP_ON_SYNC_WEDGE_THRESHOLD (30 * 1000000000ull) // nanoseconds
78#define LAST_ACTIVITY_STALL_THRESHOLD (2.0f) // seconds
79#define DROP_PEERS_ON_SCORE -2
80
81namespace cryptonote
82{
83 template <class CryptoHashContainer>
85 const std::vector<cryptonote::tx_blob_entry>& tx_entries,
86 const CryptoHashContainer& blk_tx_hashes,
87 const bool allow_pruned,
89 {
91
92 if (tx_entries.size() > blk_tx_hashes.size())
93 {
94 MERROR("Failed to make pool supplement: Too many transaction blobs!");
95 return false;
96 }
97
98 for (const cryptonote::tx_blob_entry& tx_entry: tx_entries)
99 {
100 const bool is_pruned = tx_entry.prunable_hash != crypto::null_hash;
101 if (is_pruned && !allow_pruned)
102 {
103 MERROR("Pruned transaction not allowed here");
104 return false;
105 }
106
108 crypto::hash tx_hash;
109 bool parse_success = false;
110 const bool max_size_check = true;
111 if (is_pruned)
112 {
113 if ((parse_success = cryptonote::parse_and_validate_tx_base_from_blob(tx_entry.blob, tx, max_size_check, /*require_eof=*/true)))
114 parse_success = cryptonote::get_pruned_transaction_hash(tx, tx_entry.prunable_hash, tx_hash);
115 }
116 else
117 {
118 parse_success = cryptonote::parse_and_validate_tx_from_blob(tx_entry.blob, tx, tx_hash, max_size_check);
119 }
120
121 if (!parse_success)
122 {
123 MERROR("failed to parse and/or validate transaction: "
125 );
126 return false;
127 }
128 else if (!blk_tx_hashes.count(tx_hash))
129 {
130 MERROR("transaction " << tx_hash << " not in block");
131 return false;
132 }
133
134 pool_supplement.txs_by_txid.emplace(tx_hash, std::make_pair(std::move(tx), tx_entry.blob));
135 }
136
137 return true;
138 }
139
141 const cryptonote::block_complete_entry& blk_entry,
143 {
146 {
147 MERROR("sent bad block: failed to parse and/or validate block: "
149 );
150 return false;
151 }
152
153 const std::unordered_set<crypto::hash> blk_tx_hashes(blk.tx_hashes.cbegin(), blk.tx_hashes.cend());
154
155 if (blk_tx_hashes.size() != blk_entry.txs.size())
156 {
157 MERROR("sent bad block entry: number of hashes is not equal number of tx blobs: "
159 );
160 return false;
161 }
162 else if (blk_tx_hashes.size() != blk.tx_hashes.size())
163 {
164 MERROR("sent bad block entry: there are duplicate tx hashes in parsed block: "
166 return false;
167 }
168
169 // We set `allow_pruned` equal to whether this block entry is pruned since the pruned flag
170 // should be checked anyways by the time we deserialize transactions
171 return make_pool_supplement_from_block_entry(blk_entry.txs, blk_tx_hashes, blk_entry.pruned, pool_supplement);
172 }
173
174
175 //-----------------------------------------------------------------------------------------------------------------------
176 template<class t_core>
189 //-----------------------------------------------------------------------------------------------------------------------
190 template<class t_core>
209 //------------------------------------------------------------------------------------------------------------------------
210 template<class t_core>
212 {
213 return true;
214 }
215 //------------------------------------------------------------------------------------------------------------------------
216 template<class t_core>
224 //------------------------------------------------------------------------------------------------------------------------
225 template<class t_core>
227 {
228 LOG_PRINT_CCONTEXT_L2("callback fired");
229 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);
230 --context.m_callback_request_count;
231
232 uint32_t notified = true;
233 if (context.m_idle_peer_notification.compare_exchange_strong(notified, not notified))
234 {
235 if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
236 {
237 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
238 const boost::posix_time::time_duration dt = now - context.m_last_request_time;
239 const auto ms = dt.total_microseconds();
240 if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
241 {
242 if (context.m_score-- >= 0)
243 {
244 MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
245 context.m_last_request_time = boost::date_time::not_a_date_time;
246 context.m_expect_response = 0;
247 context.m_expect_height = 0;
248 context.m_requested_objects.clear();
249 context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
250 }
251 else
252 {
253 MINFO(context << "dropping idle peer with negative score");
254 drop_connection_with_score(context, context.m_expect_response == 0 ? 1 : 5, false);
255 return false;
256 }
257 }
258 }
259 }
260
261 notified = true;
262 if (context.m_new_stripe_notification.compare_exchange_strong(notified, not notified))
263 {
264 if (context.m_state == cryptonote_connection_context::state_normal)
266 }
267
268 if(context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time == boost::posix_time::not_a_date_time)
269 {
271 context.m_needed_objects.clear();
272 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
273 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
274 r.prune = m_sync_pruned_blocks;
275 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
276 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
277 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
279 MLOG_PEER_STATE("requesting chain");
280 }
281 else if(context.m_state == cryptonote_connection_context::state_standby)
282 {
284 try_add_next_blocks(context);
285 }
286
287 return true;
288 }
289 //------------------------------------------------------------------------------------------------------------------------
290 template<class t_core>
292 {
293 std::stringstream ss;
294 ss.precision(1);
295
296 double down_sum = 0.0;
297 double down_curr_sum = 0.0;
298 double up_sum = 0.0;
299 double up_curr_sum = 0.0;
300
301 ss << std::setw(30) << std::left << "Remote Host"
302 << std::setw(20) << "Peer id"
303 << std::setw(20) << "Support Flags"
304 << std::setw(30) << "Recv/Sent (inactive,sec)"
305 << std::setw(25) << "State"
306 << std::setw(20) << "Livetime(sec)"
307 << std::setw(12) << "Down (kB/s)"
308 << std::setw(14) << "Down(now)"
309 << std::setw(10) << "Up (kB/s)"
310 << std::setw(13) << "Up(now)"
311 << ENDL;
312
313 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
314 {
315 bool local_ip = cntxt.m_remote_address.is_local();
316 auto connection_time = time(NULL) - cntxt.m_started;
317 ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
318 cntxt.m_remote_address.str()
319 << std::setw(20) << nodetool::peerid_to_string(peer_id)
320 << std::setw(20) << std::hex << support_flags
321 << std::setw(30) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
322 << std::setw(25) << get_protocol_state_string(cntxt.m_state)
323 << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
324 << std::setw(12) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_recv_cnt / connection_time / 1024)
325 << std::setw(14) << std::fixed << cntxt.m_current_speed_down / 1024
326 << std::setw(10) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_send_cnt / connection_time / 1024)
327 << std::setw(13) << std::fixed << cntxt.m_current_speed_up / 1024
328 << (local_ip ? "[LAN]" : "")
329 << std::left << (cntxt.m_remote_address.is_loopback() ? "[LOCALHOST]" : "") // 127.0.0.1
330 << ENDL;
331
332 if (connection_time > 1)
333 {
334 down_sum += (cntxt.m_recv_cnt / connection_time / 1024);
335 up_sum += (cntxt.m_send_cnt / connection_time / 1024);
336 }
337
338 down_curr_sum += (cntxt.m_current_speed_down / 1024);
339 up_curr_sum += (cntxt.m_current_speed_up / 1024);
340
341 return true;
342 });
343 ss << ENDL
344 << std::setw(125) << " "
345 << std::setw(12) << down_sum
346 << std::setw(14) << down_curr_sum
347 << std::setw(10) << up_sum
348 << std::setw(13) << up_curr_sum
349 << ENDL;
350 LOG_PRINT_L0("Connections: " << ENDL << ss.str());
351 }
352 //------------------------------------------------------------------------------------------------------------------------
353 // Returns a list of connection_info objects describing each open p2p connection
354 //------------------------------------------------------------------------------------------------------------------------
355 template<class t_core>
357 {
358 std::list<connection_info> connections;
359
360 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
361 {
362 connection_info cnx;
363 auto timestamp = time(NULL);
364
365 cnx.incoming = cntxt.m_is_income ? true : false;
366
367 cnx.address = cntxt.m_remote_address.str();
368 cnx.host = cntxt.m_remote_address.host_str();
369 cnx.ip = "";
370 cnx.port = "";
372 {
373 cnx.ip = cnx.host;
374 cnx.port = std::to_string(cntxt.m_remote_address.as<epee::net_utils::ipv4_network_address>().port());
375 }
377 {
378 cnx.ip = cnx.host;
379 cnx.port = std::to_string(cntxt.m_remote_address.as<epee::net_utils::ipv6_network_address>().port());
380 }
381 cnx.rpc_port = cntxt.m_rpc_port;
383
384 cnx.peer_id = nodetool::peerid_to_string(peer_id);
385
386 cnx.support_flags = support_flags;
387
388 cnx.recv_count = cntxt.m_recv_cnt;
389 cnx.recv_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_recv);
390
391 cnx.send_count = cntxt.m_send_cnt;
392 cnx.send_idle_time = timestamp - std::max(cntxt.m_started, cntxt.m_last_send);
393
395
396 cnx.live_time = timestamp - cntxt.m_started;
397
399 cnx.local_ip = cntxt.m_remote_address.is_local();
400
401 auto connection_time = time(NULL) - cntxt.m_started;
402 if (connection_time == 0)
403 {
404 cnx.avg_download = 0;
405 cnx.avg_upload = 0;
406 }
407
408 else
409 {
410 cnx.avg_download = cntxt.m_recv_cnt / connection_time / 1024;
411 cnx.avg_upload = cntxt.m_send_cnt / connection_time / 1024;
412 }
413
414 cnx.current_download = cntxt.m_current_speed_down / 1024;
415 cnx.current_upload = cntxt.m_current_speed_up / 1024;
416
418 cnx.ssl = cntxt.m_ssl;
419
421 cnx.pruning_seed = cntxt.m_pruning_seed;
423
424 connections.push_back(cnx);
425
426 return true;
427 });
428
429 return connections;
430 }
431 //------------------------------------------------------------------------------------------------------------------------
432 template<class t_core>
434 {
435 if(context.m_state == cryptonote_connection_context::state_before_handshake && !is_inital)
436 return true;
437
439 return true;
440
441 // from v6, if the peer advertises a top block version, reject if it's not what it should be (will only work if no voting)
442 if (hshd.current_height > 0)
443 {
444 const uint8_t version = m_core.get_ideal_hard_fork_version(hshd.current_height - 1);
445 if (version >= 6 && version != hshd.top_version)
446 {
447 if (version < hshd.top_version && version == m_core.get_ideal_hard_fork_version())
448 MDEBUG(context << " peer claims higher version than we think (" <<
449 (unsigned)hshd.top_version << " for " << (hshd.current_height - 1) << " instead of " << (unsigned)version <<
450 ") - we may be forked from the network and a software upgrade may be needed, or that peer is broken or malicious");
451 return false;
452 }
453 }
454
455 // reject weird pruning schemes
456 if (hshd.pruning_seed)
457 {
458 const uint32_t log_stripes = tools::get_pruning_log_stripes(hshd.pruning_seed);
459 if (log_stripes != CRYPTONOTE_PRUNING_LOG_STRIPES || tools::get_pruning_stripe(hshd.pruning_seed) > (1u << log_stripes))
460 {
461 MWARNING(context << " peer claim unexpected pruning seed " << epee::string_tools::to_string_hex(hshd.pruning_seed) << ", disconnecting");
462 return false;
463 }
464 }
465
466 if (hshd.current_height < context.m_remote_blockchain_height)
467 {
468 MINFO(context << "Claims " << hshd.current_height << ", claimed " << context.m_remote_blockchain_height << " before");
469 hit_score(context, 1);
470 }
471 context.m_remote_blockchain_height = hshd.current_height;
472 context.m_pruning_seed = hshd.pruning_seed;
473
474 uint64_t target = m_core.get_target_blockchain_height();
475 if (target == 0)
476 target = m_core.get_current_blockchain_height();
477
478 if(m_core.have_block(hshd.top_id))
479 {
480 context.set_state_normal();
481 if(is_inital && hshd.current_height >= target && target == m_core.get_current_blockchain_height())
483 return true;
484 }
485
486 // No chain synchronization over hidden networks (tor, i2p, etc.)
487 if(context.m_remote_address.get_zone() != epee::net_utils::zone::public_)
488 {
489 context.set_state_normal();
490 return true;
491 }
492
493 if (hshd.current_height > target)
494 {
495 /* As I don't know if accessing hshd from core could be a good practice,
496 I prefer pushing target height to the core at the same time it is pushed to the user.
497 Nz. */
498 int64_t diff = static_cast<int64_t>(hshd.current_height) - static_cast<int64_t>(m_core.get_current_blockchain_height());
499 uint64_t abs_diff = std::abs(diff);
500 uint64_t max_block_height = std::max(hshd.current_height,m_core.get_current_blockchain_height());
501 uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 624633 : m_core.get_nettype() == MAINNET ? 1009826 : (uint64_t)-1;
502 uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0;
503 MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", el::Color::Yellow, context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
504 << " [Your node is " << abs_diff << " blocks (" << tools::get_human_readable_timespan((abs_diff - diff_v2) * DIFFICULTY_TARGET_V1 + diff_v2 * DIFFICULTY_TARGET_V2) << ") "
505 << (0 <= diff ? std::string("behind") : std::string("ahead"))
506 << "] " << ENDL << "SYNCHRONIZATION started");
507 if (hshd.current_height >= m_core.get_current_blockchain_height() + 5) // don't switch to unsafe mode just for a few blocks
508 {
509 m_core.safesyncmode(false);
510 }
511 if (m_core.get_target_blockchain_height() == 0) // only when sync starts
512 {
513 m_sync_timer.resume();
514 m_sync_timer.reset();
515 m_add_timer.pause();
516 m_add_timer.reset();
523 }
524 m_core.set_target_blockchain_height((hshd.current_height));
525 }
526 MINFO(context << "Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id);
527
528 if (m_no_sync)
529 {
530 context.set_state_normal();
531 return true;
532 }
533
535 //let the socket to send response to handshake, but request callback, to let send request data after response
536 LOG_PRINT_CCONTEXT_L2("requesting callback");
537 ++context.m_callback_request_count;
538 m_p2p->request_callback(context);
539 MLOG_PEER_STATE("requesting callback");
540 context.m_num_requested = 0;
541 return true;
542 }
543 //------------------------------------------------------------------------------------------------------------------------
544 template<class t_core>
546 {
547 m_core.get_blockchain_top(hshd.current_height, hshd.top_id);
548 hshd.top_version = m_core.get_ideal_hard_fork_version(hshd.current_height);
549 difficulty_type wide_cumulative_difficulty = m_core.get_block_cumulative_difficulty(hshd.current_height);
550 hshd.cumulative_difficulty = (wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
551 hshd.cumulative_difficulty_top64 = ((wide_cumulative_difficulty >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
552 hshd.current_height +=1;
553 hshd.pruning_seed = m_core.get_blockchain_pruning_seed();
554 return true;
555 }
556 //------------------------------------------------------------------------------------------------------------------------
557 template<class t_core>
565 //------------------------------------------------------------------------------------------------------------------------
566 template<class t_core>
568 {
569 // @TODO: Eventually drop support for this endpoint
570
571 MLOGIF_P2P_MESSAGE(crypto::hash hash; cryptonote::block b; bool ret = cryptonote::parse_and_validate_block_from_blob(arg.b.block, b, &hash);, ret, context << "Received NOTIFY_NEW_BLOCK " << hash << " (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
572
573 // Redirect this request form to fluffy block handling
575 fluffy_arg.b = std::move(arg.b);
576 fluffy_arg.current_blockchain_height = arg.current_blockchain_height;
577 return handle_notify_new_fluffy_block(command, fluffy_arg, context);
578 }
579 //------------------------------------------------------------------------------------------------------------------------
580 template<class t_core>
582 {
583 // If we are synchronizing the node or setting up this connection, then do nothing
585 return 1;
586 if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
587 {
588 LOG_DEBUG_CC(context, "Received new block while syncing, ignored");
589 return 1;
590 }
591
592 // sanity check block blob size
593 if (!m_core.check_incoming_block_size(arg.b.block))
594 {
595 drop_connection(context, false, false);
597 }
598
599 // Parse and quick hash incoming block, dropping the connection on failure
600 block new_block;
601 crypto::hash new_block_hash;
602 if (!parse_and_validate_block_from_blob(arg.b.block, new_block, &new_block_hash))
603 {
605 (
606 "sent wrong block: failed to parse and validate block: "
608 << ", dropping connection"
609 );
610
611 drop_connection(context, false, false);
613 }
614
615 // Log block info
616 const uint64_t new_block_height = get_block_height(new_block);
617 const uint64_t peer_height = arg.current_blockchain_height;
618 MLOG_P2P_MESSAGE(context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << new_block_hash << " (height "
619 << new_block_height << ", " << arg.b.txs.size() << " txes, peer's height: " << peer_height << ")");
620
621 // Pause mining and resume after block verification to prevent wasted mining cycles while
622 // validating the next block. Needs more research into if this is a DoS vector or not. Invalid
623 // block validation will cause disconnects and bans, so it might not be that bad.
624 m_core.pause_mine();
625 const auto resume_mine_on_leave = epee::misc_utils::create_scope_leave_handler([this](){ m_core.resume_mine(); });
626
627 // This set allows us to quickly sanity check that the block binds all txs contained in this
628 // fluffy payload, which means that no extra stowaway txs can be harbored. In the case of a
629 // deterministic block verification failure, the peer will be punished accordingly. For other
630 // cases, *once* valid PoW will be required to perform expensive consensus checks for the txs
631 // inside the block.
632 std::unordered_map<crypto::hash, uint64_t> blk_txids_set;
633 for (size_t tx_idx = 0; tx_idx < new_block.tx_hashes.size(); ++tx_idx)
634 blk_txids_set.emplace(new_block.tx_hashes[tx_idx], tx_idx);
635
636 // Check for duplicate txids in parsed block blob
637 if (blk_txids_set.size() != new_block.tx_hashes.size())
638 {
639 MERROR("sent bad block entry: there are duplicate tx hashes in parsed block: "
641 drop_connection(context, false, false);
643 }
644
645 // Keeping a map of the full transactions provided in this payload allows us to pass them
646 // directly to core::handle_single_incoming_block() -> Blockchain::add_block(), which means we
647 // can skip the mempool for faster block propagation. Later in the function, we will erase all
648 // transactions from the relayed block.
649 pool_supplement extra_block_txs;
650 if (!make_pool_supplement_from_block_entry(arg.b.txs, blk_txids_set, /*allow_pruned=*/false, extra_block_txs))
651 {
653 (
654 "Failed to parse one or more transactions in fluffy block with ID " << new_block_hash <<
655 ", dropping connection"
656 );
657
658 drop_connection(context, false, false);
660 }
661
662 // try adding block to the blockchain
664 const bool handle_block_res = m_core.handle_single_incoming_block(arg.b.block,
665 &new_block,
666 bvc,
667 extra_block_txs);
668
669 // handle result of attempted block add
670 if (!handle_block_res || bvc.m_verifivation_failed)
671 {
672 if (bvc.m_missing_txs)
673 {
674 // Block verification failed b/c of missing transactions, so request fluffy block again with
675 // missing transactions (including the ones newly discovered in this fluffy block). Note that
676 // PoW checking happens before missing transactions checks, so if bvc.m_missing_txs is true,
677 // then that means that we passed PoW checking, so a peer can't get us to re-request fluffy
678 // blocks for free.
679
680 // Instead of requesting missing transactions by hash like BTC,
681 // we do it by index (thanks to a suggestion from moneromooo) because
682 // we're way cooler .. and also because they're smaller than hashes.
683 std::vector<uint64_t> need_tx_indices;
684 need_tx_indices.reserve(new_block.tx_hashes.size());
685
686 // Collect need_tx_indices by polling blockchain storage and mempool storage
687 for (size_t tx_idx = 0; tx_idx < new_block.tx_hashes.size(); ++tx_idx)
688 {
689 const crypto::hash &tx_hash = new_block.tx_hashes[tx_idx];
690
691 std::vector<cryptonote::blobdata> tx_blobs;
692 std::vector<crypto::hash> missed_txs;
693
694 bool need_tx = !m_core.pool_has_tx(tx_hash);
695 need_tx = need_tx && (!m_core.get_transactions({tx_hash}, tx_blobs, missed_txs, /*pruned=*/true)
696 || !missed_txs.empty());
697
698 if (need_tx)
699 need_tx_indices.push_back(tx_idx);
700 }
701
702 // Make request form
703 MDEBUG("We are missing " << need_tx_indices.size() << " txes for this fluffy block");
704 for (auto txidx: need_tx_indices)
705 MDEBUG(" tx " << new_block.tx_hashes[txidx]);
707 missing_tx_req.block_hash = new_block_hash;
708 missing_tx_req.current_blockchain_height = new_block_height + 1;
709 missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
710
711 // Post NOTIFY_REQUEST_FLUFFY_MISSING_TX request to peer
712 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_FLUFFY_MISSING_TX: missing_tx_indices.size()=" << missing_tx_req.missing_tx_indices.size() );
713 post_notify<NOTIFY_REQUEST_FLUFFY_MISSING_TX>(missing_tx_req, context);
714 }
715 else // failure for some other reason besides missing txs...
716 {
717 // drop connection and punish peer
718 LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
721 }
722 }
723 else if( bvc.m_added_to_main_chain )
724 {
725 arg.current_blockchain_height = new_block_height + 1;
726 // Relay an empty block
727 arg.b.txs.clear();
728 relay_block(arg, context);
729 }
730 else if( bvc.m_marked_as_orphaned )
731 {
732 context.m_needed_objects.clear();
735 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
736 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
737 r.prune = m_sync_pruned_blocks;
738 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
739 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
740 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
742 MLOG_PEER_STATE("requesting chain");
743 }
744
746 {
747 // Update peer's sync height using this block we just validated
748 // Note: peer_height is not guaranteed to be the height of the block we just validated + 1.
749 // See https://github.com/monero-project/monero/pull/11048#discussion_r3720736824
750 if (peer_height == (new_block_height + 1))
751 context.m_remote_blockchain_height = peer_height;
752 }
753
754 // load json & DNS checkpoints every 10min/hour respectively,
755 // and verify them with respect to what blocks we already have
756 CHECK_AND_ASSERT_MES(m_core.update_checkpoints(), 1, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
757
758 return 1;
759 }
760 //------------------------------------------------------------------------------------------------------------------------
761 template<class t_core>
763 {
764 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
766 {
767 LOG_ERROR_CCONTEXT("Requested fluffy tx before handshake, dropping connection");
768 drop_connection(context, false, false);
770 }
771
772 std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
773 std::vector<cryptonote::blobdata> local_txs;
774
775 block b;
776 if (!m_core.get_block_by_hash(arg.block_hash, b))
777 {
778 LOG_ERROR_CCONTEXT("failed to find block: " << arg.block_hash << ", dropping connection");
779 drop_connection(context, false, false);
781 }
782
783 std::vector<crypto::hash> txids;
784 txids.reserve(b.tx_hashes.size());
785 NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
786 fluffy_response.b.block = t_serializable_object_to_blob(b);
787 fluffy_response.current_blockchain_height = arg.current_blockchain_height;
788 std::vector<bool> seen(b.tx_hashes.size(), false);
789 for(auto& tx_idx: arg.missing_tx_indices)
790 {
791 if(tx_idx < b.tx_hashes.size())
792 {
793 MDEBUG(" tx " << b.tx_hashes[tx_idx]);
794 if (seen[tx_idx])
795 {
797 (
798 "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
799 << ", request is asking for duplicate tx "
800 << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
801 << ", block_height = " << arg.current_blockchain_height
802 << ", dropping connection"
803 );
804 drop_connection(context, true, false);
806 }
807 txids.push_back(b.tx_hashes[tx_idx]);
808 seen[tx_idx] = true;
809 }
810 else
811 {
813 (
814 "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
815 << ", request is asking for a tx whose index is out of bounds "
816 << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
817 << ", block_height = " << arg.current_blockchain_height
818 << ", dropping connection"
819 );
820
821 drop_connection(context, false, false);
823 }
824 }
825
826 std::vector<cryptonote::transaction> txs;
827 std::vector<crypto::hash> missed;
828 if (!m_core.get_transactions(txids, txs, missed))
829 {
830 LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
831 << "failed to get requested transactions");
832 drop_connection(context, false, false);
834 }
835 if (!missed.empty() || txs.size() != txids.size())
836 {
837 LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
838 << missed.size() << " requested transactions not found" << ", dropping connection");
839 drop_connection(context, false, false);
841 }
842
843 for(auto& tx: txs)
844 {
845 fluffy_response.b.txs.push_back({t_serializable_object_to_blob(tx), crypto::null_hash});
846 }
847
849 (
850 "-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
851 << ", txs.size()=" << fluffy_response.b.txs.size()
852 << ", rsp.current_blockchain_height=" << fluffy_response.current_blockchain_height
853 );
854
855 post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_response, context);
856 return 1;
857 }
858 //------------------------------------------------------------------------------------------------------------------------
859 template<class t_core>
861 {
862 MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
864 return 1;
865
866 std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
867 std::vector<cryptonote::blobdata> local_txs;
868
869 std::vector<cryptonote::blobdata> txes;
870 if (!m_core.get_txpool_complement(std::move(arg.hashes), txes))
871 {
872 LOG_ERROR_CCONTEXT("failed to get txpool complement");
873 return 1;
874 }
875
877 new_txes.txs = std::move(txes);
878
880 (
881 "-->>NOTIFY_NEW_TRANSACTIONS: "
882 << ", txs.size()=" << new_txes.txs.size()
883 );
884
885 post_notify<NOTIFY_NEW_TRANSACTIONS>(new_txes, context);
886 return 1;
887 }
888 //------------------------------------------------------------------------------------------------------------------------
889 template<class t_core>
891 {
892 MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
893 std::unordered_set<crypto::hash> seen;
894 seen.reserve(arg.txs.size());
895
896 for (const auto &blob: arg.txs)
897 {
898 MLOGIF_P2P_MESSAGE(cryptonote::transaction tx; crypto::hash hash; bool ret = cryptonote::parse_and_validate_tx_from_blob(blob, tx, hash, true);, ret, "Including transaction " << hash);
899
900 crypto::hash digest{};
901 if (!blob.empty())
902 tools::sha256sum(reinterpret_cast<const uint8_t*>(blob.data()), blob.size(), digest);
903
904 if (!seen.insert(digest).second)
905 {
906 LOG_PRINT_CCONTEXT_L1("Duplicate transaction in notification, dropping connection");
907 drop_connection(context, false, false);
909 }
910 }
911
913 return 1;
914
915 // while syncing, core will lock for a long time, so we ignore
916 // those txes as they aren't really needed anyway, and avoid a
917 // long block before replying
918 if(!is_synchronized())
919 {
920 LOG_DEBUG_CC(context, "Received new tx while syncing, ignored");
921 return 1;
922 }
923
924 /* If the txes were received over i2p/tor, the default is to "forward"
925 with a randomized delay to further enhance the "white noise" behavior,
926 potentially making it harder for ISP-level spies to determine which
927 inbound link sent the tx. If the sender disabled "white noise" over
928 i2p/tor, then the sender is "fluffing" (to only outbound) i2p/tor
929 connections with the `dandelionpp_fluff` flag set. The receiver (hidden
930 service) will immediately fluff in that scenario (i.e. this assumes that a
931 sybil spy will be unable to link an IP to an i2p/tor connection). */
932
933 const epee::net_utils::zone zone = context.m_remote_address.get_zone();
936
937 std::vector<blobdata> stem_txs{};
938 std::vector<blobdata> fluff_txs{};
939 if (arg.dandelionpp_fluff)
940 {
941 tx_relay = relay_method::fluff;
942 fluff_txs.reserve(arg.txs.size());
943 }
944 else
945 stem_txs.reserve(arg.txs.size());
946
947 for (auto& tx : arg.txs)
948 {
950 if (!m_core.handle_incoming_tx(tx, tvc, tx_relay, true) && !tvc.m_no_drop_offense)
951 {
952 LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
953 drop_connection(context, false, false);
955 }
956
957 switch (tvc.m_relay)
958 {
961 stem_txs.push_back(std::move(tx));
962 break;
965 fluff_txs.push_back(std::move(tx));
966 break;
967 default:
968 case relay_method::forward: // not supposed to happen here
970 break;
971 }
972 }
973
974 if (!stem_txs.empty())
975 {
976 //TODO: add announce usage here
977 arg.dandelionpp_fluff = false;
978 arg.txs = std::move(stem_txs);
979 relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone(), relay_method::stem);
980 }
981 if (!fluff_txs.empty())
982 {
983 //TODO: add announce usage here
984 arg.dandelionpp_fluff = true;
985 arg.txs = std::move(fluff_txs);
986 relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone(), relay_method::fluff);
987 }
988 return 1;
989 }
990 //------------------------------------------------------------------------------------------------------------------------
991 template<class t_core>
993 {
995 {
996 LOG_ERROR_CCONTEXT("Requested objects before handshake, dropping connection");
997 drop_connection(context, false, false);
999 }
1000 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
1001 if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
1002 {
1004 "Requested objects count is too big ("
1005 << arg.blocks.size() << ") expected not more then "
1007 drop_connection(context, false, false);
1009 }
1010
1012 if(!m_core.handle_get_objects(arg, rsp, context))
1013 {
1014 LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection");
1015 drop_connection(context, false, false);
1017 }
1018 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
1019 MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
1020 << rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
1021 << ", missed_ids.size()=" << rsp.missed_ids.size());
1023 //handler_response_blocks_now(sizeof(rsp)); // XXX
1024 //handler_response_blocks_now(200);
1025 return 1;
1026 }
1027 //------------------------------------------------------------------------------------------------------------------------
1028
1029
1030 template<class t_core>
1032 {
1034 if (m_avg_buffer.empty()) {
1035 MWARNING("m_avg_buffer.size() == 0");
1036 return 500;
1037 }
1038 double avg = 0;
1039 for (const auto &element : m_avg_buffer) avg += element;
1040 return avg / m_avg_buffer.size();
1041 }
1042
1043 template<class t_core>
1045 {
1046 MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
1047 MLOG_PEER_STATE("received objects");
1048
1049 boost::posix_time::ptime request_time = context.m_last_request_time;
1050 context.m_last_request_time = boost::date_time::not_a_date_time;
1051
1052 if (context.m_expect_response != NOTIFY_RESPONSE_GET_OBJECTS::ID)
1053 {
1054 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_GET_OBJECTS out of the blue, dropping connection");
1055 drop_connection(context, true, false);
1057 }
1058 context.m_expect_response = 0;
1059
1060 // calculate size of request
1061 size_t size = 0;
1062 size_t blocks_size = 0;
1063 for (const auto &element : arg.blocks) {
1064 blocks_size += element.block.size();
1065 for (const auto &tx : element.txs)
1066 blocks_size += tx.blob.size();
1067 }
1068 size += blocks_size;
1069
1070 for (const auto &element : arg.missed_ids)
1071 size += sizeof(element.data);
1072
1073 size += sizeof(arg.current_blockchain_height);
1074 {
1076 m_avg_buffer.push_back(size);
1077 }
1080 MDEBUG(context << " downloaded " << size << " bytes worth of blocks");
1081
1082 /*using namespace boost::chrono;
1083 auto point = steady_clock::now();
1084 auto time_from_epoh = point.time_since_epoch();
1085 auto sec = duration_cast< seconds >( time_from_epoh ).count();*/
1086
1087 //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
1088
1089 if(arg.blocks.empty())
1090 {
1091 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks");
1092 drop_connection(context, true, false);
1095 }
1096 if(context.m_last_response_height > arg.current_blockchain_height)
1097 {
1098 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
1099 << " < m_last_response_height=" << context.m_last_response_height << ", dropping connection");
1100 drop_connection(context, false, false);
1103 }
1104
1105 if (arg.current_blockchain_height < context.m_remote_blockchain_height)
1106 {
1107 MINFO(context << "Claims " << arg.current_blockchain_height << ", claimed " << context.m_remote_blockchain_height << " before");
1108 hit_score(context, 1);
1109 if (context.m_score <= DROP_PEERS_ON_SCORE)
1111 }
1112 context.m_remote_blockchain_height = arg.current_blockchain_height;
1113 if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
1114 m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
1115
1116 std::vector<crypto::hash> block_hashes;
1117 block_hashes.reserve(arg.blocks.size());
1118 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1119 uint64_t start_height = std::numeric_limits<uint64_t>::max();
1120 crypto::hash previous{};
1122 for(std::size_t i = 0; i < arg.blocks.size(); ++i)
1123 {
1124 if (m_stopping)
1125 {
1126 return 1;
1127 }
1128
1129 crypto::hash block_hash;
1130 if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash))
1131 {
1132 LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
1133 << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
1134 drop_connection(context, false, false);
1137 }
1138 if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
1139 {
1140 LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
1141 << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
1142 drop_connection(context, false, false);
1145 }
1146
1147 const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
1148 if (context.get_expected_hash(this_height) != block_hash)
1149 {
1150 LOG_ERROR_CCONTEXT("Sent invalid chain");
1151 drop_connection(context, false, false);
1154 }
1155
1156 // if first block
1157 if (start_height == std::numeric_limits<uint64_t>::max())
1158 {
1159 start_height = this_height;
1160 if (start_height > context.m_expect_height)
1161 {
1162 LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
1163 drop_connection(context, false, false);
1166 }
1167
1168 if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id)
1169 {
1170 LOG_ERROR_CCONTEXT("Sent invalid chain");
1171 drop_connection(context, false, false);
1174 }
1175 }
1176 else if (b.prev_id != previous)
1177 {
1178 LOG_ERROR_CCONTEXT("Sent invalid chain");
1179 drop_connection(context, false, false);
1182 }
1183 previous = block_hash;
1184
1185 if (start_height + i != this_height)
1186 {
1187 LOG_ERROR_CCONTEXT("Sent invalid chain");
1188 drop_connection(context, false, false);
1191 }
1192
1193 auto req_it = context.m_requested_objects.find(block_hash);
1194 if(req_it == context.m_requested_objects.end())
1195 {
1196 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
1197 << " wasn't requested, dropping connection");
1198 drop_connection(context, false, false);
1201 }
1202 if(b.tx_hashes.size() != arg.blocks[i].txs.size())
1203 {
1204 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
1205 << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection");
1206 drop_connection(context, false, false);
1209 }
1210
1211 context.m_requested_objects.erase(req_it);
1212 block_hashes.push_back(block_hash);
1213 }
1214
1215 if(!context.m_requested_objects.empty())
1216 {
1217 MERROR(context << "returned not all requested objects (context.m_requested_objects.size()="
1218 << context.m_requested_objects.size() << "), dropping connection");
1219 drop_connection(context, false, false);
1222 }
1223
1224 const bool pruned_ok = should_ask_for_pruned_data(context, start_height, arg.blocks.size(), true);
1225 if (!pruned_ok)
1226 {
1227 // if we don't want pruned data, check we did not get any
1228 for (block_complete_entry& block_entry: arg.blocks)
1229 {
1230 if (block_entry.pruned)
1231 {
1232 MERROR(context << "returned a pruned block, dropping connection");
1233 drop_connection(context, false, false);
1236 }
1237 if (block_entry.block_weight)
1238 {
1239 MERROR(context << "returned a block weight for a non pruned block, dropping connection");
1240 drop_connection(context, false, false);
1243 }
1244 for (const tx_blob_entry &tx_entry: block_entry.txs)
1245 {
1246 if (tx_entry.prunable_hash != crypto::null_hash)
1247 {
1248 MERROR(context << "returned at least one pruned object which we did not expect, dropping connection");
1249 drop_connection(context, false, false);
1252 }
1253 }
1254 }
1255 }
1256 else
1257 {
1258 // we accept pruned data, check that if we got some, then no weights are zero
1259 for (block_complete_entry& block_entry: arg.blocks)
1260 {
1261 if (block_entry.block_weight == 0 && block_entry.pruned)
1262 {
1263 MERROR(context << "returned at least one pruned block with 0 weight, dropping connection");
1264 drop_connection(context, false, false);
1267 }
1268 }
1269 }
1270
1271 {
1272 MLOG_YELLOW(el::Level::Debug, context << " Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size()
1273 << ", blocks: " << start_height << " - " << (start_height + arg.blocks.size() - 1) <<
1274 " (pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ")");
1275
1276 // add that new span to the block queue
1277 const boost::posix_time::time_duration dt = now - request_time;
1278 const float rate = size * 1e6 / (dt.total_microseconds() + 1);
1279 MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1024) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
1280 m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, context.m_remote_address, rate, blocks_size);
1281
1282 const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
1283 context.m_last_known_hash = last_block_hash;
1284
1285 if (!m_core.get_test_drop_download() || !m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
1286 return 1;
1287 }
1288 }
1289
1290 try_add_next_blocks(context);
1291 return 1;
1292 }
1293
1294 // Get an estimate for the remaining sync time from given current to target blockchain height, in seconds
1295 template<class t_core>
1297 {
1298 // The average sync speed varies so much, even averaged over quite long time periods like 10 minutes,
1299 // that using some sliding window would be difficult to implement without often leading to bad estimates.
1300 // The simplest strategy - always average sync speed over the maximum available interval i.e. since sync
1301 // started at all (from "m_sync_start_time" and "m_sync_start_height") - gives already useful results
1302 // and seems to be quite robust. Some quite special cases like "Internet connection suddenly becoming
1303 // much faster after syncing already a long time, and staying fast" are not well supported however.
1304
1305 if (target_blockchain_height <= current_blockchain_height)
1306 {
1307 // Syncing stuck, or other special circumstance: Avoid errors, simply give back 0
1308 return 0;
1309 }
1310
1311 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1312 const boost::posix_time::time_duration sync_time = now - m_sync_start_time;
1313 cryptonote::network_type nettype = m_core.get_nettype();
1314
1315 // Don't simply use remaining number of blocks for the estimate but "sync weight" as provided by
1316 // "cumulative_block_sync_weight" which knows about strongly varying Monero mainnet block sizes
1317 uint64_t synced_weight = tools::cumulative_block_sync_weight(nettype, m_sync_start_height, current_blockchain_height - m_sync_start_height);
1318 float us_per_weight = (float)sync_time.total_microseconds() / (float)synced_weight;
1319 uint64_t remaining_weight = tools::cumulative_block_sync_weight(nettype, current_blockchain_height, target_blockchain_height - current_blockchain_height);
1320 float remaining_us = us_per_weight * (float)remaining_weight;
1321 return (uint64_t)(remaining_us / 1e6);
1322 }
1323
1324 // Return a textual remaining sync time estimate, or the empty string if waiting period not yet over
1325 template<class t_core>
1326 std::string t_cryptonote_protocol_handler<t_core>::get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
1327 {
1328 std::string text = "";
1329 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1330 boost::posix_time::time_duration period_sync_time = now - m_period_start_time;
1331 if (period_sync_time > boost::posix_time::minutes(2))
1332 {
1333 // Period is over, time to report another estimate
1334 uint64_t remaining_seconds = get_estimated_remaining_sync_seconds(current_blockchain_height, target_blockchain_height);
1335 text = tools::get_human_readable_timespan(remaining_seconds);
1336
1337 // Start the new period
1338 m_period_start_time = now;
1339 }
1340 return text;
1341 }
1342
1343 template<class t_core>
1345 {
1346 bool force_next_span = false;
1347
1348 {
1349 // We try to lock the sync lock. If we can, it means no other thread is
1350 // currently adding blocks, so we do that for as long as we can from the
1351 // block queue. Then, we go back to download.
1352 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
1353 if (!sync.owns_lock())
1354 {
1355 MINFO(context << "Failed to lock m_sync_lock, going back to download");
1356 goto skip;
1357 }
1358 MDEBUG(context << " lock m_sync_lock, adding blocks to chain...");
1359 MLOG_PEER_STATE("adding blocks");
1360
1361 {
1362 m_core.pause_mine();
1363 m_add_timer.resume();
1364 bool starting = true;
1366 m_add_timer.pause();
1367 m_core.resume_mine();
1368 if (!starting)
1370 });
1371 m_sync_start_time = boost::posix_time::microsec_clock::universal_time();
1372 m_sync_start_height = m_core.get_current_blockchain_height();
1374
1375 while (1)
1376 {
1377 const uint64_t previous_height = m_core.get_current_blockchain_height();
1378 uint64_t start_height;
1379 std::vector<cryptonote::block_complete_entry> blocks;
1380 boost::uuids::uuid span_connection_id;
1382 if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin))
1383 {
1384 MDEBUG(context << " no next span found, going back to download");
1385 break;
1386 }
1387
1388 if (blocks.empty())
1389 {
1390 MERROR(context << "Next span has no blocks");
1391 m_block_queue.remove_spans(span_connection_id, start_height);
1392 continue;
1393 }
1394
1395 MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
1396 << ", we need " << previous_height);
1397
1398 block new_block;
1399 crypto::hash last_block_hash;
1400 if (!parse_and_validate_block_from_blob(blocks.back().block, new_block, last_block_hash))
1401 {
1402 MERROR(context << "Failed to parse block, but it should already have been parsed");
1403 m_block_queue.remove_spans(span_connection_id, start_height);
1404 continue;
1405 }
1406 if (m_core.have_block(last_block_hash))
1407 {
1408 const uint64_t subchain_height = start_height + blocks.size();
1409 LOG_DEBUG_CC(context, "These are old blocks, ignoring: blocks " << start_height << " - " << (subchain_height-1) << ", blockchain height " << m_core.get_current_blockchain_height());
1410 m_block_queue.remove_spans(span_connection_id, start_height);
1412 continue;
1413 }
1414 if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
1415 {
1416 MERROR(context << "Failed to parse block, but it should already have been parsed");
1417 m_block_queue.remove_spans(span_connection_id, start_height);
1418 continue;
1419 }
1420 bool parent_known = m_core.have_block(new_block.prev_id);
1421 if (!parent_known)
1422 {
1423 const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id);
1424 if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height)
1425 {
1426 MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id);
1427 drop_connection(span_connection_id);
1428 return 1;
1429 }
1430
1431 // it could be:
1432 // - later in the current chain
1433 // - later in an alt chain
1434 // - orphan
1435 // if it was requested, then it'll be resolved later, otherwise it's an orphan
1436 bool parent_requested = m_block_queue.requested(new_block.prev_id);
1437 if (!parent_requested)
1438 {
1439 // we might be able to ask for that block directly, as we now can request out of order,
1440 // otherwise we continue out of order, unless this block is the one we need, in which
1441 // case we request block hashes, though it might be safer to disconnect ?
1442 if (start_height > previous_height)
1443 {
1445 {
1446 MDEBUG(context << "Got block with unknown parent which was not requested, but peer does not have that block - dropping connection");
1447 if (!context.m_is_income)
1448 m_p2p->add_used_stripe_peer(context);
1449 drop_connection(context, false, true);
1450 return 1;
1451 }
1452 MDEBUG(context << "Got block with unknown parent which was not requested, but peer does not have that block - back to download");
1453
1454 goto skip;
1455 }
1456
1457 // this can happen if a connection was sicced onto a late span, if it did not have those blocks,
1458 // since we don't know that at the sic time
1459 LOG_ERROR_CCONTEXT("Got block with unknown parent which was not requested - querying block hashes");
1460 m_block_queue.remove_spans(span_connection_id, start_height);
1461 context.m_needed_objects.clear();
1462 context.m_last_response_height = 0;
1463 goto skip;
1464 }
1465
1466 // parent was requested, so we wait for it to be retrieved
1467 MINFO(context << " parent was requested, we'll get back to it");
1468 break;
1469 }
1470
1471 const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
1472
1473 if (starting)
1474 {
1475 starting = false;
1477 {
1478 const uint64_t tnow = tools::get_tick_count();
1480 MINFO("Restarting adding block after idle for " << ns/1e9 << " seconds");
1481 }
1482 }
1483
1484 std::vector<block> pblocks;
1485 if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
1486 {
1487 LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
1488 m_block_queue.flush_spans(span_connection_id, true);
1489 drop_connections(span_origin);
1490 return 1;
1491 }
1492 if (!pblocks.empty() && pblocks.size() != blocks.size())
1493 {
1494 m_core.cleanup_handle_incoming_blocks();
1495 LOG_ERROR_CCONTEXT("Internal error: blocks.size() != block_entry.txs.size()");
1496 return 1;
1497 }
1498
1499 bool stopped = false;
1500 auto cleanup_on_exit = epee::misc_utils::create_scope_leave_handler([this, &stopped, &context, span_connection_id, start_height]() {
1501 if (!m_core.cleanup_handle_incoming_blocks())
1502 {
1503 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1504 return;
1505 }
1506
1507 if (stopped)
1508 return;
1509
1510 m_block_queue.remove_spans(span_connection_id, start_height);
1511 });
1512
1513 uint64_t block_process_time_full = 0, transactions_process_time_full = 0;
1514 size_t num_txs = 0, blockidx = 0;
1515 for(const block_complete_entry& block_entry: blocks)
1516 {
1517 if (m_stopping)
1518 {
1519 stopped = true;
1520 return 1;
1521 }
1522
1523 // process transactions
1524 TIME_MEASURE_START(transactions_process_time);
1525 num_txs += block_entry.txs.size();
1526
1527 pool_supplement block_txs;
1528 if (!make_full_pool_supplement_from_block_entry(block_entry, block_txs))
1529 {
1530 drop_connections(span_origin);
1531 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1532 LOG_ERROR_CCONTEXT("transaction parsing failed for 1 or more txs in NOTIFY_RESPONSE_GET_OBJECTS,"
1533 "dropping connections");
1534 drop_connection(context, false, true);
1535 return 1;
1536 }))
1537 LOG_ERROR_CCONTEXT("span connection id not found");
1538
1539 return 1;
1540 }
1541 TIME_MEASURE_FINISH(transactions_process_time);
1542 transactions_process_time_full += transactions_process_time;
1543
1544 // process block
1545
1546 TIME_MEASURE_START(block_process_time);
1548
1549 m_core.handle_incoming_block(block_entry.block,
1550 pblocks.empty() ? NULL : &pblocks[blockidx],
1551 bvc,
1552 block_txs,
1553 false); // <--- process block
1554
1555 if(bvc.m_verifivation_failed)
1556 {
1557 drop_connections(span_origin);
1558 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1559 LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
1560 drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
1561 return 1;
1562 }))
1563 LOG_ERROR_CCONTEXT("span connection id not found");
1564
1565 return 1;
1566 }
1567 if(bvc.m_marked_as_orphaned)
1568 {
1569 drop_connections(span_origin);
1570 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1571 LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
1572 drop_connection(context, true, true);
1573 return 1;
1574 }))
1575 LOG_ERROR_CCONTEXT("span connection id not found");
1576
1577 return 1;
1578 }
1579
1580 TIME_MEASURE_FINISH(block_process_time);
1581 block_process_time_full += block_process_time;
1582 ++blockidx;
1583
1584 } // each download block
1585
1586 MDEBUG(context << "Block process time (" << blocks.size() << " blocks, " << num_txs << " txs): " << block_process_time_full + transactions_process_time_full << " (" << transactions_process_time_full << "/" << block_process_time_full << ") ms");
1587
1588 cleanup_on_exit.reset();
1589
1590 const uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
1591 if (current_blockchain_height > previous_height)
1592 {
1593 const uint64_t target_blockchain_height = m_core.get_target_blockchain_height();
1594 const boost::posix_time::time_duration dt = boost::posix_time::microsec_clock::universal_time() - start;
1595 std::string progress_message = "";
1596 if (current_blockchain_height < target_blockchain_height)
1597 {
1598 uint64_t completion_percent = (current_blockchain_height * 100 / target_blockchain_height);
1599 if (completion_percent == 100) // never show 100% if not actually up to date
1600 completion_percent = 99;
1601 progress_message = " (" + std::to_string(completion_percent) + "%, "
1602 + std::to_string(target_blockchain_height - current_blockchain_height) + " left";
1603 std::string time_message = get_periodic_sync_estimate(current_blockchain_height, target_blockchain_height);
1604 if (!time_message.empty())
1605 {
1606 uint64_t total_blocks_to_sync = target_blockchain_height - m_sync_start_height;
1607 uint64_t total_blocks_synced = current_blockchain_height - m_sync_start_height;
1608 progress_message += ", " + std::to_string(total_blocks_synced * 100 / total_blocks_to_sync) + "% of total synced";
1609 progress_message += ", estimated " + time_message + " left";
1610 }
1611 progress_message += ")";
1612 }
1613 const uint32_t previous_stripe = tools::get_pruning_stripe(previous_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1614 const uint32_t current_stripe = tools::get_pruning_stripe(current_blockchain_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1615 std::string timing_message = "";
1616 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
1617 timing_message = std::string(" (") + std::to_string(dt.total_microseconds()/1e6) + " sec, "
1618 + std::to_string((current_blockchain_height - previous_height) * 1e6 / dt.total_microseconds())
1619 + " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued in "
1620 + std::to_string(m_block_queue.get_num_filled_spans()) + " spans, stripe "
1621 + std::to_string(previous_stripe) + " -> " + std::to_string(current_stripe);
1622 if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info"))
1623 timing_message += std::string(": ") + m_block_queue.get_overview(current_blockchain_height);
1624 MGINFO_YELLOW("Synced " << current_blockchain_height << "/" << target_blockchain_height
1625 << progress_message << timing_message);
1626 if (previous_stripe != current_stripe)
1627 notify_new_stripe(context, current_stripe);
1628 }
1629 }
1630 }
1631
1632 MLOG_PEER_STATE("stopping adding blocks");
1633
1634 if (should_download_next_span(context, false))
1635 {
1636 force_next_span = true;
1637 }
1638 else if (should_drop_connection(context, get_next_needed_pruning_stripe().first))
1639 {
1640 if (!context.m_is_income)
1641 {
1642 m_p2p->add_used_stripe_peer(context);
1643 drop_connection(context, false, false);
1644 }
1645 return 1;
1646 }
1647 }
1648
1649skip:
1650 if (!request_missing_objects(context, true, force_next_span))
1651 {
1652 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
1653 drop_connection(context, false, false);
1654 return 1;
1655 }
1656 return 1;
1657 }
1658 //------------------------------------------------------------------------------------------------------------------------
1659 template<class t_core>
1661 {
1662 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1663 {
1664 if (cntxt.m_connection_id == context.m_connection_id)
1665 return true;
1666 if (context.m_state == cryptonote_connection_context::state_normal)
1667 {
1668 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1669 if (stripe && peer_stripe && peer_stripe != stripe)
1670 return true;
1671 context.m_new_stripe_notification = true;
1672 LOG_PRINT_CCONTEXT_L2("requesting callback");
1673 ++context.m_callback_request_count;
1674 m_p2p->request_callback(context);
1675 MLOG_PEER_STATE("requesting callback");
1676 }
1677 return true;
1678 });
1679 }
1680 //------------------------------------------------------------------------------------------------------------------------
1681 template<class t_core>
1689 //------------------------------------------------------------------------------------------------------------------------
1690 template<class t_core>
1692 {
1693 MTRACE("Checking for idle peers...");
1694 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1695 {
1696 if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
1697 {
1698 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1699 const boost::posix_time::time_duration dt = now - context.m_last_request_time;
1700 const auto ms = dt.total_microseconds();
1701 if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
1702 {
1703 context.m_idle_peer_notification = true;
1704 LOG_PRINT_CCONTEXT_L2("requesting callback");
1705 ++context.m_callback_request_count;
1706 m_p2p->request_callback(context);
1707 MLOG_PEER_STATE("requesting callback");
1708 }
1709 }
1710 return true;
1711 });
1712
1713 return true;
1714 }
1715 //------------------------------------------------------------------------------------------------------------------------
1716 template<class t_core>
1718 {
1719 const uint64_t target = m_core.get_target_blockchain_height();
1720 const uint64_t height = m_core.get_current_blockchain_height();
1721 if (target > height) // if we're not synced yet, don't do it
1722 return true;
1723
1724 MTRACE("Checking for outgoing syncing peers...");
1725 std::unordered_map<epee::net_utils::zone, unsigned> n_syncing, n_synced;
1726 std::unordered_map<epee::net_utils::zone, boost::uuids::uuid> last_synced_peer_id;
1727 std::vector<epee::net_utils::zone> zones;
1728 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1729 {
1730 if (!peer_id || context.m_is_income) // only consider connected outgoing peers
1731 return true;
1732
1733 const epee::net_utils::zone zone = context.m_remote_address.get_zone();
1734 if (n_syncing.find(zone) == n_syncing.end())
1735 {
1736 n_syncing[zone] = 0;
1737 n_synced[zone] = 0;
1738 last_synced_peer_id[zone] = boost::uuids::nil_uuid();
1739 zones.push_back(zone);
1740 }
1741
1743 ++n_syncing[zone];
1744 if (context.m_state == cryptonote_connection_context::state_normal)
1745 {
1746 ++n_synced[zone];
1747 if (!context.m_anchor)
1748 last_synced_peer_id[zone] = context.m_connection_id;
1749 }
1750 return true;
1751 });
1752
1753 for (const auto& zone : zones)
1754 {
1755 const unsigned int max_out_peers = get_max_out_peers(zone);
1756 MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1757
1758 // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor
1759 if (n_synced[zone] + n_syncing[zone] >= max_out_peers && n_syncing[zone] < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id[zone] != boost::uuids::nil_uuid())
1760 {
1761 if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1762 MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1763 drop_connection(ctx, false, false);
1764 return true;
1765 }))
1766 MDEBUG("Failed to find peer we wanted to drop");
1767 }
1768 }
1769
1770 return true;
1771 }
1772 //------------------------------------------------------------------------------------------------------------------------
1773 template<class t_core>
1775 {
1776 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1777 {
1778 if (context.m_state == cryptonote_connection_context::state_standby)
1779 {
1780 LOG_PRINT_CCONTEXT_L2("requesting callback");
1781 ++context.m_callback_request_count;
1782 m_p2p->request_callback(context);
1783 }
1784 return true;
1785 });
1786 return true;
1787 }
1788 //------------------------------------------------------------------------------------------------------------------------
1789 template<class t_core>
1791 {
1792 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
1794 {
1795 LOG_ERROR_CCONTEXT("Requested chain before handshake, dropping connection");
1796 drop_connection(context, false, false);
1798 }
1800 if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
1801 {
1802 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
1803 return 1;
1804 }
1805 if (r.m_block_ids.size() >= 2)
1806 {
1808 if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
1809 {
1810 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
1811 return 1;
1812 }
1813 r.first_block = cryptonote::block_to_blob(b);
1814 }
1815 MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
1817 return 1;
1818 }
1819 //------------------------------------------------------------------------------------------------------------------------
1820 template<class t_core>
1822 {
1823 std::vector<crypto::hash> hashes;
1824 boost::posix_time::ptime request_time;
1825 boost::uuids::uuid connection_id;
1826 bool filled;
1827
1828 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
1829 if (context.m_remote_blockchain_height <= blockchain_height)
1830 return false;
1831 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1832 const bool has_next_block = tools::has_unpruned_block(blockchain_height, context.m_remote_blockchain_height, context.m_pruning_seed);
1833 if (has_next_block)
1834 {
1835 if (!m_block_queue.has_next_span(blockchain_height, filled, request_time, connection_id))
1836 {
1837 MDEBUG(context << " we should download it as no peer reserved it");
1838 return true;
1839 }
1840 if (!filled)
1841 {
1842 const long dt = (now - request_time).total_microseconds();
1844 {
1845 MDEBUG(context << " we should download it as it's not been received yet after " << dt/1e6);
1846 return true;
1847 }
1848
1849 // in standby, be ready to double download early since we're idling anyway
1850 // let the fastest peer trigger first
1851 const double dl_speed = context.m_max_speed_down;
1852 if (standby && dt >= REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY && dl_speed > 0)
1853 {
1854 bool download = false;
1855 if (m_p2p->for_connection(connection_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1856 const time_t nowt = time(NULL);
1857 const time_t time_since_last_recv = nowt - ctx.m_last_recv;
1858 const float last_activity = std::min((float)time_since_last_recv, dt/1e6f);
1859 const bool stalled = last_activity > LAST_ACTIVITY_STALL_THRESHOLD;
1860 if (stalled)
1861 {
1862 MDEBUG(context << " we should download it as the downloading peer is stalling for " << nowt - ctx.m_last_recv << " seconds");
1863 download = true;
1864 return true;
1865 }
1866
1867 // estimate the standby peer can give us 80% of its max speed
1868 // and let it download if that speed is > N times as fast as the current one
1869 // N starts at 10 after REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY,
1870 // decreases to 1.25 at REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD,
1871 // so that at times goes without the download being done, a retry becomes easier
1872 const float max_multiplier = 10.f;
1873 const float min_multiplier = 1.25f;
1874 float multiplier = max_multiplier;
1876 {
1877 multiplier = max_multiplier - (dt-REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY) * (max_multiplier - min_multiplier) / (REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD - REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY);
1878 multiplier = std::min(max_multiplier, std::max(min_multiplier, multiplier));
1879 }
1880 if (dl_speed * .8f > ctx.m_current_speed_down * multiplier)
1881 {
1882 MDEBUG(context << " we should download it as we are substantially faster (" << dl_speed << " vs "
1883 << ctx.m_current_speed_down << ", multiplier " << multiplier << " after " << dt/1e6 << " seconds)");
1884 download = true;
1885 return true;
1886 }
1887 return true;
1888 }))
1889 {
1890 if (download)
1891 return true;
1892 }
1893 else
1894 {
1895 MWARNING(context << " we should download it as the downloading peer is unexpectedly not known to us");
1896 return true;
1897 }
1898 }
1899 }
1900 }
1901
1902 return false;
1903 }
1904 //------------------------------------------------------------------------------------------------------------------------
1905 template<class t_core>
1907 {
1908 if (context.m_anchor)
1909 {
1910 MDEBUG(context << "This is an anchor peer, not dropping");
1911 return false;
1912 }
1913 if (context.m_pruning_seed == 0)
1914 {
1915 MDEBUG(context << "This peer is not striped, not dropping");
1916 return false;
1917 }
1918
1919 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1920 if (next_stripe == peer_stripe)
1921 {
1922 MDEBUG(context << "This peer has needed stripe " << peer_stripe << ", not dropping");
1923 return false;
1924 }
1925 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1926 if (m_sync_pruned_blocks && local_stripe && next_stripe != local_stripe)
1927 {
1928 MDEBUG(context << "We can sync pruned blocks off this peer, not dropping");
1929 return false;
1930 }
1931
1932 if (!context.m_needed_objects.empty())
1933 {
1934 const uint64_t next_available_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
1935 if (tools::has_unpruned_block(next_available_block_height, context.m_remote_blockchain_height, context.m_pruning_seed))
1936 {
1937 MDEBUG(context << "This peer has unpruned next block at height " << next_available_block_height << ", not dropping");
1938 return false;
1939 }
1940 }
1941
1942 if (next_stripe > 0)
1943 {
1944 unsigned int n_out_peers = 0, n_peers_on_next_stripe = 0;
1945 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
1946 if (!ctx.m_is_income)
1947 ++n_out_peers;
1949 ++n_peers_on_next_stripe;
1950 return true;
1951 });
1952 // TODO: investigate tallying by zone and comparing to max out peers by zone
1953 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
1954 const uint32_t distance = (peer_stripe + (1<<CRYPTONOTE_PRUNING_LOG_STRIPES) - next_stripe) % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
1955 if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2)
1956 {
1957 MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers ("
1958 << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe <<
1959 " is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space");
1960 return true;
1961 }
1962 }
1963 MDEBUG(context << "End of checks, not dropping");
1964 return false;
1965 }
1966 //------------------------------------------------------------------------------------------------------------------------
1967 template<class t_core>
1969 {
1970 // take out blocks we already have
1971 size_t skip = 0;
1972 while (skip < context.m_needed_objects.size() && (m_core.have_block(context.m_needed_objects[skip].first) || (check_block_queue && m_block_queue.have(context.m_needed_objects[skip].first))))
1973 {
1974 // if we're popping the last hash, record it so we can ask again from that hash,
1975 // this prevents never being able to progress on peers we get old hash lists from
1976 if (skip + 1 == context.m_needed_objects.size())
1977 context.m_last_known_hash = context.m_needed_objects[skip].first;
1978 ++skip;
1979 }
1980 if (skip > 0)
1981 {
1982 MDEBUG(context << "skipping " << skip << "/" << context.m_needed_objects.size() << " blocks");
1983 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
1984 }
1985 return skip;
1986 }
1987 //------------------------------------------------------------------------------------------------------------------------
1988 template<class t_core>
1989 bool t_cryptonote_protocol_handler<t_core>::should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const
1990 {
1992 return false;
1993 if (!m_core.is_within_compiled_block_hash_area(first_block_height + nblocks - 1))
1994 return false;
1995 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1996 if (local_stripe == 0)
1997 return false;
1998 // don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
1999 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP + 1);
2000 if (first_block_height < bp_fork_height)
2001 return false;
2002 // assumes the span size is less or equal to the stripe size
2003 bool full_data_needed = tools::get_pruning_stripe(first_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe
2004 || tools::get_pruning_stripe(first_block_height + nblocks - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe;
2005 if (full_data_needed)
2006 return false;
2007 if (check_block_weights && !m_core.has_block_weights(first_block_height, nblocks))
2008 return false;
2009 return true;
2010 }
2011 //------------------------------------------------------------------------------------------------------------------------
2012 template<class t_core>
2013 bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks, bool force_next_span)
2014 {
2015 // flush stale spans
2016 std::set<boost::uuids::uuid> live_connections;
2017 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2018 live_connections.insert(context.m_connection_id);
2019 return true;
2020 });
2021 m_block_queue.flush_stale_spans(live_connections);
2022
2023 // if we don't need to get next span, and the block queue is full enough, wait a bit
2024 if (!force_next_span)
2025 {
2026 do
2027 {
2028 size_t nspans = m_block_queue.get_num_filled_spans();
2029 size_t size = m_block_queue.get_data_size();
2030 const uint64_t bc_height = m_core.get_current_blockchain_height();
2031 const auto next_needed_pruning_stripe = get_next_needed_pruning_stripe();
2032 const uint32_t add_stripe = tools::get_pruning_stripe(bc_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2033 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2034 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
2035 const size_t block_queue_size_threshold = m_block_download_max_size ? m_block_download_max_size : BLOCK_QUEUE_SIZE_THRESHOLD;
2036 bool queue_proceed = nspans < BLOCK_QUEUE_NSPANS_THRESHOLD || size < block_queue_size_threshold;
2037 // get rid of blocks we already requested, or already have
2038 if (skip_unneeded_hashes(context, true) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2039 {
2040 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(bc_height))
2041 {
2042 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2043 return false;
2044 }
2045 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2046 context.set_state_normal();
2047 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2049 return true;
2050 }
2051 uint64_t next_needed_height = m_block_queue.get_next_needed_height(bc_height);
2052 uint64_t next_block_height;
2053 if (context.m_needed_objects.empty())
2054 next_block_height = next_needed_height;
2055 else
2056 next_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2057 bool stripe_proceed_main = ((m_sync_pruned_blocks && local_stripe && add_stripe != local_stripe) || add_stripe == 0 || peer_stripe == 0 || add_stripe == peer_stripe) && (next_block_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS || next_needed_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS);
2058 bool stripe_proceed_secondary = tools::has_unpruned_block(next_block_height, context.m_remote_blockchain_height, context.m_pruning_seed);
2059 bool proceed = stripe_proceed_main || (queue_proceed && stripe_proceed_secondary);
2060 if (!stripe_proceed_main && !stripe_proceed_secondary && should_drop_connection(context, tools::get_pruning_stripe(next_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)))
2061 {
2062 if (!context.m_is_income)
2063 m_p2p->add_used_stripe_peer(context);
2064 return false; // drop outgoing connections
2065 }
2066
2067 MDEBUG(context << "proceed " << proceed << " (queue " << queue_proceed << ", stripe " << stripe_proceed_main << "/" <<
2068 stripe_proceed_secondary << "), " << next_needed_pruning_stripe.first << "-" << next_needed_pruning_stripe.second <<
2069 " needed, bc add stripe " << add_stripe << ", we have " << peer_stripe << "), bc_height " << bc_height);
2070 MDEBUG(context << " - next_block_height " << next_block_height << ", seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2071 ", next_needed_height "<< next_needed_height);
2072 MDEBUG(context << " - last_response_height " << context.m_last_response_height << ", m_needed_objects size " << context.m_needed_objects.size());
2073
2074 // if we're waiting for next span, try to get it before unblocking threads below,
2075 // or a runaway downloading of future spans might happen
2076 if (stripe_proceed_main && should_download_next_span(context, true))
2077 {
2078 MDEBUG(context << " we should try for that next span too, we think we could get it faster, resuming");
2079 force_next_span = true;
2080 MLOG_PEER_STATE("resuming");
2081 break;
2082 }
2083
2084 if (proceed)
2085 {
2086 if (context.m_state != cryptonote_connection_context::state_standby)
2087 {
2088 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", resuming");
2089 MLOG_PEER_STATE("resuming");
2090 }
2091 break;
2092 }
2093
2094 // this one triggers if all threads are in standby, which should not happen,
2095 // but happened at least once, so we unblock at least one thread if so
2096 boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2097 if (sync.owns_lock())
2098 {
2099 bool filled = false;
2100 boost::posix_time::ptime time;
2101 boost::uuids::uuid connection_id;
2102 if (m_block_queue.has_next_span(m_core.get_current_blockchain_height(), filled, time, connection_id) && filled)
2103 {
2104 LOG_DEBUG_CC(context, "No other thread is adding blocks, and next span needed is ready, resuming");
2105 MLOG_PEER_STATE("resuming");
2107 ++context.m_callback_request_count;
2108 m_p2p->request_callback(context);
2109 return true;
2110 }
2111 else
2112 {
2113 sync.unlock();
2114
2115 // if this has gone on for too long, drop incoming connection to guard against some wedge state
2116 if (!context.m_is_income)
2117 {
2118 const uint64_t now = tools::get_tick_count();
2119 const uint64_t dt = now - m_last_add_end_time;
2121 {
2122 MDEBUG(context << "ns " << tools::ticks_to_ns(dt) << " from " << m_last_add_end_time << " and " << now);
2123 MDEBUG(context << "Block addition seems to have wedged, dropping connection");
2124 return false;
2125 }
2126 }
2127 }
2128 }
2129
2130 if (context.m_state != cryptonote_connection_context::state_standby)
2131 {
2132 if (!queue_proceed)
2133 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", pausing");
2134 else if (!stripe_proceed_main && !stripe_proceed_secondary)
2135 LOG_DEBUG_CC(context, "We do not have the stripe required to download another block, pausing");
2137 MLOG_PEER_STATE("pausing");
2138 }
2139
2140 return true;
2141 } while(0);
2143 }
2144
2145 MDEBUG(context << " request_missing_objects: check " << check_having_blocks << ", force_next_span " << force_next_span
2146 << ", m_needed_objects " << context.m_needed_objects.size() << " lrh " << context.m_last_response_height << ", chain "
2147 << m_core.get_current_blockchain_height() << ", pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed));
2148 if(context.m_needed_objects.size() || force_next_span)
2149 {
2150 //we know objects that we need, request this objects
2152 bool is_next = false;
2153 size_t count = 0;
2154 const size_t count_limit = m_core.get_block_sync_size(m_core.get_current_blockchain_height());
2155 std::pair<uint64_t, uint64_t> span = std::make_pair(0, 0);
2156 if (force_next_span)
2157 {
2158 if (span.second == 0)
2159 {
2160 std::vector<crypto::hash> hashes;
2161 boost::uuids::uuid span_connection_id;
2162 boost::posix_time::ptime time;
2163 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2164 if (span.second > 0)
2165 {
2166 is_next = true;
2167 req.blocks.reserve(hashes.size());
2168 for (const auto &hash: hashes)
2169 {
2170 req.blocks.push_back(hash);
2171 context.m_requested_objects.insert(hash);
2172 }
2173 m_block_queue.reset_next_span_time();
2174 }
2175 }
2176 }
2177 if (span.second == 0)
2178 {
2179 MDEBUG(context << " span size is 0");
2180 if (context.m_last_response_height + 1 < context.m_needed_objects.size())
2181 {
2182 MERROR(context << " ERROR: inconsistent context: lrh " << context.m_last_response_height << ", nos " << context.m_needed_objects.size());
2183 context.m_needed_objects.clear();
2184 context.m_last_response_height = 0;
2185 goto skip;
2186 }
2187 if (skip_unneeded_hashes(context, false) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2188 {
2189 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(m_core.get_current_blockchain_height()))
2190 {
2191 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2192 return false;
2193 }
2194 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2195 context.set_state_normal();
2196 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2198 return true;
2199 }
2200
2201 const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2202 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
2203 bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
2204 span = m_block_queue.reserve_span(first_block_height, context.m_last_response_height, count_limit, context.m_connection_id, context.m_remote_address, sync_pruned_blocks, m_core.get_blockchain_pruning_seed(), context.m_pruning_seed, context.m_remote_blockchain_height, context.m_needed_objects);
2205 MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
2206 if (span.second > 0)
2207 {
2208 const uint32_t stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2209 if (context.m_pruning_seed && stripe != tools::get_pruning_stripe(context.m_pruning_seed))
2210 {
2211 MDEBUG(context << " starting early on next seed (" << span.first << " with stripe " << stripe <<
2212 ", context seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ")");
2213 }
2214 }
2215 }
2216 if (span.second == 0 && !force_next_span)
2217 {
2218 MDEBUG(context << " still no span reserved, we may be in the corner case of next span scheduled and everything else scheduled/filled");
2219 std::vector<crypto::hash> hashes;
2220 boost::uuids::uuid span_connection_id;
2221 boost::posix_time::ptime time;
2222 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2223 if (span.second > 0 && !tools::has_unpruned_block(span.first, context.m_remote_blockchain_height, context.m_pruning_seed))
2224 span = std::make_pair(0, 0);
2225 if (span.second > 0)
2226 {
2227 is_next = true;
2228 req.blocks.reserve(hashes.size());
2229 for (const auto &hash: hashes)
2230 {
2231 req.blocks.push_back(hash);
2232 ++count;
2233 context.m_requested_objects.insert(hash);
2234 // that's atrocious O(n) wise, but this is rare
2235 auto i = std::find_if(context.m_needed_objects.begin(), context.m_needed_objects.end(),
2236 [&hash](const std::pair<crypto::hash, uint64_t> &o) { return o.first == hash; });
2237 if (i != context.m_needed_objects.end())
2238 context.m_needed_objects.erase(i);
2239 }
2240 }
2241 }
2242 MDEBUG(context << " span: " << span.first << "/" << span.second << " (" << span.first << " - " << (span.first + span.second - 1) << ")");
2243 if (span.second > 0)
2244 {
2245 if (!is_next)
2246 {
2247 const uint64_t first_context_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2248 uint64_t skip = span.first - first_context_block_height;
2249 if (skip > context.m_needed_objects.size())
2250 {
2251 MERROR("ERROR: skip " << skip << ", m_needed_objects " << context.m_needed_objects.size() << ", first_context_block_height" << first_context_block_height);
2252 return false;
2253 }
2254 if (skip > 0)
2255 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
2256 if (context.m_needed_objects.size() < span.second)
2257 {
2258 MERROR("ERROR: span " << span.first << "/" << span.second << ", m_needed_objects " << context.m_needed_objects.size());
2259 return false;
2260 }
2261
2262 req.blocks.reserve(req.blocks.size() + span.second);
2263 for (size_t n = 0; n < span.second; ++n)
2264 {
2265 req.blocks.push_back(context.m_needed_objects[n].first);
2266 ++count;
2267 context.m_requested_objects.insert(context.m_needed_objects[n].first);
2268 }
2269 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + span.second, context.m_needed_objects.end());
2270 }
2271
2272 req.prune = should_ask_for_pruned_data(context, span.first, span.second, true);
2273
2274 // if we need to ask for full data and that peer does not have the right stripe, we can't ask it
2275 if (!req.prune && context.m_pruning_seed)
2276 {
2277 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2278 const uint32_t first_stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2279 const uint32_t last_stripe = tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2280 if (((first_stripe && peer_stripe != first_stripe) || (last_stripe && peer_stripe != last_stripe)) && !m_sync_pruned_blocks)
2281 {
2282 MDEBUG(context << "We need full data, but the peer does not have it, dropping peer");
2283 return false;
2284 }
2285 }
2286 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2287 context.m_expect_height = span.first;
2288 context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
2289 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
2290 << "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
2291 //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
2292
2293 MDEBUG("Asking for " << (req.prune ? "pruned" : "full") << " data, start/end "
2294 << tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2295 << "/" << tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2296 << ", ours " << tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed()) << ", peer stripe " << tools::get_pruning_stripe(context.m_pruning_seed));
2297
2298 context.m_num_requested += req.blocks.size();
2300 MLOG_PEER_STATE("requesting objects");
2301 return true;
2302 }
2303
2304 // we can do nothing, so drop this peer to make room for others unless we think we've downloaded all we need
2305 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
2306 if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
2307 {
2308 context.set_state_normal();
2309 MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
2310 return true;
2311 }
2312 MLOG_PEER_STATE("We can download nothing from this peer, dropping");
2313 return false;
2314 }
2315
2316skip:
2317 context.m_needed_objects.clear();
2318
2319 // we might have been called from the "received chain entry" handler, and end up
2320 // here because we can't use any of those blocks (maybe because all of them are
2321 // actually already requested). In this case, if we can add blocks instead, do so
2322 if (m_core.get_current_blockchain_height() < m_core.get_target_blockchain_height())
2323 {
2324 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2325 if (sync.owns_lock())
2326 {
2327 uint64_t start_height;
2328 std::vector<cryptonote::block_complete_entry> blocks;
2329 boost::uuids::uuid span_connection_id;
2331 if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
2332 {
2333 LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
2334 MLOG_PEER_STATE("will try to add blocks next");
2336 ++context.m_callback_request_count;
2337 m_p2p->request_callback(context);
2338 return true;
2339 }
2340 }
2341 }
2342
2343 if(context.m_last_response_height < context.m_remote_blockchain_height-1)
2344 {//we have to fetch more objects ids, request blockchain entry
2345
2347 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
2348 CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
2349
2350 // we'll want to start off from where we are on that peer, which may not be added yet
2351 if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
2352 {
2353 context.m_expect_height = std::numeric_limits<uint64_t>::max();
2354 r.block_ids.push_front(context.m_last_known_hash);
2355 }
2356
2357 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
2358 r.prune = m_sync_pruned_blocks;
2359
2360 //std::string blob; // for calculate size of request
2361 //epee::serialization::store_t_to_binary(r, blob);
2362 //epee::net_utils::network_throttle_manager::get_global_throttle_inreq().logger_handle_net("log/dr-monero/net/req-all.data", sec, get_avg_block_size());
2363 //LOG_PRINT_CCONTEXT_L1("r = " << 200);
2364
2365 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2366 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
2367 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
2369 MLOG_PEER_STATE("requesting chain");
2370 }else
2371 {
2372 CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1
2373 && !context.m_needed_objects.size()
2374 && !context.m_requested_objects.size(), false, "request_missing_blocks final condition failed!"
2375 << "\r\nm_last_response_height=" << context.m_last_response_height
2376 << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height
2377 << "\r\nm_needed_objects.size()=" << context.m_needed_objects.size()
2378 << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
2379 << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
2380
2381 context.set_state_normal();
2382 if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
2383 {
2384 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2386 }
2387 else
2388 {
2389 MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
2390 }
2391 }
2392 return true;
2393 }
2394 //------------------------------------------------------------------------------------------------------------------------
2395 template<class t_core>
2397 {
2398 bool val_expected = false;
2399 uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
2400 if(!m_core.is_within_compiled_block_hash_area(current_blockchain_height) && m_synchronized.compare_exchange_strong(val_expected, true))
2401 {
2402 if ((current_blockchain_height > m_sync_start_height) && (m_sync_spans_downloaded > 0))
2403 {
2404 uint64_t synced_blocks = current_blockchain_height - m_sync_start_height;
2405 // Report only after syncing an "interesting" number of blocks:
2406 if (synced_blocks > 20)
2407 {
2408 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2409 uint64_t synced_seconds = (now - m_sync_start_time).total_seconds();
2410 if (synced_seconds == 0)
2411 {
2412 synced_seconds = 1;
2413 }
2414 float blocks_per_second = (1000 * synced_blocks / synced_seconds) / 1000.0f;
2415 MGINFO_YELLOW("Synced " << synced_blocks << " blocks in "
2416 << tools::get_human_readable_timespan(synced_seconds) << " (" << blocks_per_second << " blocks per second)");
2417 }
2418 }
2419 MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
2420 << "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
2421 << ENDL
2422 << "Use the \"help\" command to see the list of available commands." << ENDL
2423 << "**********************************************************************");
2424 m_sync_timer.pause();
2425 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
2426 {
2427 const uint64_t sync_time = m_sync_timer.value();
2428 const uint64_t add_time = m_add_timer.value();
2429 if (sync_time && add_time)
2430 {
2431 MCLOG_YELLOW(el::Level::Info, "sync-info", "Sync time: " << sync_time/1e9/60 << " min, idle time " <<
2432 (100.f * (1.0f - add_time / (float)sync_time)) << "%" << ", " <<
2433 (10 * m_sync_download_objects_size / 1024 / 1024) / 10.f << " + " <<
2434 (10 * m_sync_download_chain_size / 1024 / 1024) / 10.f << " MB downloaded, " <<
2435 100.0f * m_sync_old_spans_downloaded / m_sync_spans_downloaded << "% old spans, " <<
2436 100.0f * m_sync_bad_spans_downloaded / m_sync_spans_downloaded << "% bad spans");
2437 }
2438 }
2439 m_core.on_synchronized();
2440 }
2441 m_core.safesyncmode(true);
2442 m_p2p->clear_used_stripe_peers();
2443
2444 // ask for txpool complement from any suitable node if we did not yet
2445 val_expected = true;
2446 if (m_ask_for_txpool_complement.compare_exchange_strong(val_expected, false))
2447 {
2448 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
2449 {
2451 {
2452 MDEBUG(context << "not ready, ignoring");
2453 return true;
2454 }
2455 if (!request_txpool_complement(context))
2456 {
2457 MERROR(context << "Failed to request txpool complement");
2458 return true;
2459 }
2460 return false;
2461 });
2462 }
2463
2464 return true;
2465 }
2466 //------------------------------------------------------------------------------------------------------------------------
2467 template<class t_core>
2469 {
2470 size_t count = 0;
2471 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2473 ++count;
2474 return true;
2475 });
2476 return count;
2477 }
2478 //------------------------------------------------------------------------------------------------------------------------
2479 template<class t_core>
2481 {
2482 MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
2483 << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height << ", expect height=" << context.m_expect_height);
2484 MLOG_PEER_STATE("received chain");
2485
2486 if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
2487 {
2488 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
2489 drop_connection(context, true, false);
2491 }
2492 context.m_expect_response = 0;
2493 if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
2494 {
2495 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
2496 drop_connection(context, true, false);
2498 }
2499
2500 context.m_last_request_time = boost::date_time::not_a_date_time;
2501
2502 m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
2503
2504 if(!arg.m_block_ids.size())
2505 {
2506 LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
2507 drop_connection(context, true, false);
2509 }
2510 if (arg.total_height < arg.m_block_ids.size() || arg.start_height > arg.total_height - arg.m_block_ids.size())
2511 {
2512 LOG_ERROR_CCONTEXT("sent invalid start/nblocks/height, dropping connection");
2513 drop_connection(context, true, false);
2515 }
2516 if (!arg.m_block_weights.empty() && arg.m_block_weights.size() != arg.m_block_ids.size())
2517 {
2518 LOG_ERROR_CCONTEXT("sent invalid block weight array, dropping connection");
2519 drop_connection(context, true, false);
2521 }
2522 MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back());
2523
2524 if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() > BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT)
2525 {
2526 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size());
2527 drop_connection(context, false, false);
2529 }
2530 if (arg.total_height < context.m_remote_blockchain_height)
2531 {
2532 MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
2533 hit_score(context, 1);
2534 if (context.m_score <= DROP_PEERS_ON_SCORE)
2536 }
2537 context.m_remote_blockchain_height = arg.total_height;
2538 context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
2539 if(context.m_last_response_height > context.m_remote_blockchain_height)
2540 {
2541 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
2542 << ", m_start_height=" << arg.start_height
2543 << ", m_block_ids.size()=" << arg.m_block_ids.size());
2544 drop_connection(context, false, false);
2546 }
2547
2548 uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
2549 if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
2550 {
2551 LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection");
2552 drop_connection(context, true, false);
2554 }
2555
2556 context.m_expected_heights_start = arg.start_height;
2557
2558 context.m_expected_heights.clear();
2559 context.m_expected_heights.reserve(arg.m_block_ids.size());
2560 context.m_needed_objects.clear();
2561 context.m_needed_objects.reserve(arg.m_block_ids.size());
2562 uint64_t added = 0;
2563 std::unordered_set<crypto::hash> blocks_found;
2564 bool expect_unknown = false;
2565 for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
2566 {
2567 if (!blocks_found.insert(arg.m_block_ids[i]).second)
2568 {
2569 LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
2570 drop_connection_with_score(context, 5, false);
2572 }
2573 int where;
2574 const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
2575 if (i == 0)
2576 {
2577 // our outgoing chainlist only has proven blocks (i.e. downloaded)
2578 if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
2579 {
2580 LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
2581 drop_connection_with_score(context, 5, false);
2583 }
2584 if (!have_block)
2585 expect_unknown = true;
2586 }
2587 if (0 < i)
2588 {
2589 // after the first, blocks may be known or unknown, but if they are known,
2590 // they should be at the same height if on the main chain
2591 if (have_block)
2592 {
2593 switch (where)
2594 {
2595 default:
2596 case HAVE_BLOCK_INVALID:
2597 LOG_ERROR_CCONTEXT("Block is invalid or known without known type, dropping connection");
2598 drop_connection(context, true, false);
2601 if (expect_unknown)
2602 {
2603 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2604 drop_connection_with_score(context, 5, false);
2606 }
2607 if (m_core.get_block_id_by_height(arg.start_height + i) != arg.m_block_ids[i])
2608 {
2609 LOG_ERROR_CCONTEXT("Block is on the main chain, but not at the expected height, dropping connection");
2610 drop_connection_with_score(context, 5, false);
2612 }
2613 break;
2615 if (expect_unknown)
2616 {
2617 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2618 drop_connection_with_score(context, 5, false);
2620 }
2621 break;
2622 }
2623 }
2624 else
2625 expect_unknown = true;
2626 }
2627 const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
2628 context.m_expected_heights.push_back(arg.m_block_ids[i]);
2629 context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
2630 if (++added == n_use_blocks)
2631 break;
2632 }
2633 context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
2634
2635 if (!request_missing_objects(context, false))
2636 {
2637 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
2638 drop_connection(context, false, false);
2639 return 1;
2640 }
2641
2642 if (arg.total_height > m_core.get_target_blockchain_height())
2643 m_core.set_target_blockchain_height(arg.total_height);
2644
2645 context.m_num_requested = 0;
2646 return 1;
2647 }
2648 //------------------------------------------------------------------------------------------------------------------------
2649 template<class t_core>
2651 {
2652 // sort peers between fluffy ones and others
2653 std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> fluffyConnections;
2654 m_p2p->for_each_connection([this, &exclude_context, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
2655 {
2656 // peer_id also filters out connections before handshake
2657 if (peer_id && exclude_context.m_connection_id != context.m_connection_id && context.m_remote_address.get_zone() == epee::net_utils::zone::public_)
2658 {
2659 LOG_DEBUG_CC(context, "RELAYING FLUFFY BLOCK TO PEER");
2660 fluffyConnections.push_back({context.m_remote_address.get_zone(), context.m_connection_id});
2661 }
2662 return true;
2663 });
2664
2665 // send fluffy ones first, we want to encourage people to run that
2666 if (!fluffyConnections.empty())
2667 {
2668 epee::levin::message_writer fluffyBlob{32 * 1024};
2670 m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, std::move(fluffyBlob), std::move(fluffyConnections));
2671 }
2672
2673 return true;
2674 }
2675 //------------------------------------------------------------------------------------------------------------------------
2676 template<class t_core>
2678 {
2679 /* Push all outgoing transactions to this function. The behavior needs to
2680 identify how the transaction is going to be relayed, and then update the
2681 local mempool before doing the relay. The code was already updating the
2682 DB twice on received transactions - it is difficult to workaround this
2683 due to the internal design. */
2684 return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid;
2685 }
2686 //------------------------------------------------------------------------------------------------------------------------
2687 template<class t_core>
2689 {
2691 if (!m_core.get_pool_transaction_hashes(r.hashes, false))
2692 {
2693 MERROR("Failed to get txpool hashes");
2694 return false;
2695 }
2696 MLOG_P2P_MESSAGE("-->>NOTIFY_GET_TXPOOL_COMPLEMENT: hashes.size()=" << r.hashes.size() );
2698 MLOG_PEER_STATE("requesting txpool complement");
2699 return true;
2700 }
2701 //------------------------------------------------------------------------------------------------------------------------
2702 template<class t_core>
2704 {
2705 if (score <= 0)
2706 {
2707 MERROR("Negative score hit");
2708 return;
2709 }
2710 context.m_score -= score;
2711 if (context.m_score <= DROP_PEERS_ON_SCORE)
2712 drop_connection_with_score(context, 5, false);
2713 }
2714 //------------------------------------------------------------------------------------------------------------------------
2715 template<class t_core>
2717 {
2718 std::stringstream ss;
2719 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2720 m_p2p->for_each_connection([&](const connection_context &ctx, nodetool::peerid_type peer_id, uint32_t support_flags) {
2722 char state_char = cryptonote::get_protocol_state_char(ctx.m_state);
2723 ss << stripe + state_char;
2724 if (ctx.m_last_request_time != boost::date_time::not_a_date_time)
2725 ss << (((now - ctx.m_last_request_time).total_microseconds() > IDLE_PEER_KICK_TIME) ? "!" : "?");
2726 ss << + " ";
2727 return true;
2728 });
2729 return ss.str();
2730 }
2731 //------------------------------------------------------------------------------------------------------------------------
2732 template<class t_core>
2734 {
2735 const uint64_t want_height_from_blockchain = m_core.get_current_blockchain_height();
2736 const uint64_t want_height_from_block_queue = m_block_queue.get_next_needed_height(want_height_from_blockchain);
2737 const uint64_t want_height = std::max(want_height_from_blockchain, want_height_from_block_queue);
2738 uint64_t blockchain_height = m_core.get_target_blockchain_height();
2739 // if we don't know the remote chain size yet, assume infinitely large so we get the right stripe if we're not near the tip
2740 if (blockchain_height == 0)
2741 blockchain_height = CRYPTONOTE_MAX_BLOCK_NUMBER;
2742 const uint32_t next_pruning_stripe = tools::get_pruning_stripe(want_height, blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2743 if (next_pruning_stripe == 0)
2744 return std::make_pair(0, 0);
2745 // if we already have a few peers on this stripe, but none on next one, try next one
2746 unsigned int n_next = 0, n_subsequent = 0, n_others = 0;
2747 const uint32_t subsequent_pruning_stripe = 1 + next_pruning_stripe % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
2748 m_p2p->for_each_connection([&](const connection_context &context, nodetool::peerid_type peer_id, uint32_t support_flags) {
2750 {
2751 if (context.m_pruning_seed == 0 || tools::get_pruning_stripe(context.m_pruning_seed) == next_pruning_stripe)
2752 ++n_next;
2753 else if (tools::get_pruning_stripe(context.m_pruning_seed) == subsequent_pruning_stripe)
2754 ++n_subsequent;
2755 else
2756 ++n_others;
2757 }
2758 return true;
2759 });
2760 // TODO: investigate tallying by zone and comparing to max out peers by zone
2761 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
2762 const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0);
2763 const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe;
2764 MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" <<
2765 want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " <<
2766 next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " <<
2767 subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" <<
2768 (ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) <<
2769 "), current peers " << po);
2770 return std::make_pair(next_pruning_stripe, ret_stripe);
2771 }
2772 //------------------------------------------------------------------------------------------------------------------------
2773 template<class t_core>
2775 {
2776 const uint64_t target = m_core.get_target_blockchain_height();
2777 const uint64_t height = m_core.get_current_blockchain_height();
2778 if (target && target <= height)
2779 return false;
2780 size_t n_out_peers = 0;
2781 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2782 if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone)
2783 ++n_out_peers;
2784 return true;
2785 });
2786 if (n_out_peers >= get_max_out_peers(zone))
2787 return false;
2788 return true;
2789 }
2790 //------------------------------------------------------------------------------------------------------------------------
2791 template<class t_core>
2793 {
2794 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2795 return !sync.owns_lock();
2796 }
2797 //------------------------------------------------------------------------------------------------------------------------
2798 template<class t_core>
2800 {
2801 LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
2802 epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2803 "), score " << score << ", flush_all_spans " << flush_all_spans);
2804
2805 if (score > 0)
2806 m_p2p->add_host_fail(context.m_remote_address, score);
2807
2808 m_block_queue.flush_spans(context.m_connection_id, flush_all_spans);
2809
2810 m_p2p->drop_connection(context);
2811 }
2812 //------------------------------------------------------------------------------------------------------------------------
2813 template<class t_core>
2815 {
2816 return drop_connection_with_score(context, add_fail ? 1 : 0, flush_all_spans);
2817 }
2818 //------------------------------------------------------------------------------------------------------------------------
2819 template<class t_core>
2821 {
2822 m_block_queue.flush_spans(id, true);
2823 m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2824 // This _could be_ outside of strand, so careful on actions
2825 drop_connection(context, true, false);
2826 return true;
2827 });
2828 }
2829 //------------------------------------------------------------------------------------------------------------------------
2830 template<class t_core>
2832 {
2833 MWARNING("dropping connections to " << address.str());
2834
2835 m_p2p->add_host_fail(address, 5);
2836
2837 std::vector<boost::uuids::uuid> drop;
2838 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2839 if (address.is_same_host(cntxt.m_remote_address))
2840 drop.push_back(cntxt.m_connection_id);
2841 return true;
2842 });
2843 for (const boost::uuids::uuid &id: drop)
2844 {
2845 m_block_queue.flush_spans(id, true);
2846 m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2847 // This _could be_ outside of strand, so careful on actions
2848 drop_connection(context, true, false);
2849 return true;
2850 });
2851 }
2852 }
2853 //------------------------------------------------------------------------------------------------------------------------
2854 template<class t_core>
2856 {
2857 uint64_t target = 0;
2858 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2859 if (cntxt.m_state >= cryptonote_connection_context::state_synchronizing && cntxt.m_connection_id != context.m_connection_id)
2860 target = std::max(target, cntxt.m_remote_blockchain_height);
2861 return true;
2862 });
2863 const uint64_t previous_target = m_core.get_target_blockchain_height();
2864 if (target < previous_target)
2865 {
2866 MINFO("Target height decreasing from " << previous_target << " to " << target);
2867 m_core.set_target_blockchain_height(target);
2868 if (target < m_core.get_current_blockchain_height() + 5)
2869 m_core.safesyncmode(true);
2870 if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
2871 {
2872 MCWARNING("global", "monerod is now disconnected from the network");
2874 }
2875 }
2876
2877 m_block_queue.flush_spans(context.m_connection_id, false);
2878 MLOG_PEER_STATE("closed");
2879 }
2880
2881 //------------------------------------------------------------------------------------------------------------------------
2882 template<class t_core>
2884 {
2885 m_stopping = true;
2886 m_core.stop();
2887 }
2888} // namespace
2889
cryptonote::block b
Definition block.cpp:40
void handler_request_blocks_history(std::list< crypto::hash > &ids)
Definition cryptonote_protocol_handler-base.cpp:99
std::atomic< bool > m_ask_for_txpool_complement
Definition cryptonote_protocol_handler.h:179
uint64_t get_estimated_remaining_sync_seconds(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
Definition cryptonote_protocol_handler.inl:1296
bool m_sync_pruned_blocks
Definition cryptonote_protocol_handler.h:193
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans)
Definition cryptonote_protocol_handler.inl:2814
virtual bool is_synchronized() const final
Definition cryptonote_protocol_handler.h:110
epee::math_helper::once_a_time_seconds< 101 > m_sync_search_checker
Definition cryptonote_protocol_handler.h:184
uint64_t m_last_add_end_time
Definition cryptonote_protocol_handler.h:189
std::pair< uint32_t, uint32_t > get_next_needed_pruning_stripe() const
Definition cryptonote_protocol_handler.inl:2733
bool get_payload_sync_data(epee::byte_slice &data)
Definition cryptonote_protocol_handler.inl:558
t_cryptonote_protocol_handler(t_core &rcore, nodetool::i_p2p_endpoint< connection_context > *p_net_layout, bool offline=false)
Definition cryptonote_protocol_handler.inl:177
void set_p2p_endpoint(nodetool::i_p2p_endpoint< connection_context > *p2p)
Definition cryptonote_protocol_handler.inl:217
int handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:890
bool request_missing_objects(cryptonote_connection_context &context, bool check_having_blocks, bool force_next_span=false)
Definition cryptonote_protocol_handler.inl:2013
uint64_t m_sync_download_chain_size
Definition cryptonote_protocol_handler.h:191
std::atomic< bool > m_no_sync
Definition cryptonote_protocol_handler.h:178
bool post_notify(typename t_parameter::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.h:210
void hit_score(cryptonote_connection_context &context, int32_t score)
Definition cryptonote_protocol_handler.inl:2703
boost::mutex m_buffer_mutex
Definition cryptonote_protocol_handler.h:203
std::string get_peers_overview() const
Definition cryptonote_protocol_handler.inl:2716
bool process_payload_sync_data(const CORE_SYNC_DATA &hshd, cryptonote_connection_context &context, bool is_inital)
Definition cryptonote_protocol_handler.inl:433
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe)
Definition cryptonote_protocol_handler.inl:1660
double get_avg_block_size()
Definition cryptonote_protocol_handler.inl:1031
std::string get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
Definition cryptonote_protocol_handler.inl:1326
bool should_ask_for_pruned_data(cryptonote_connection_context &context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const
Definition cryptonote_protocol_handler.inl:1989
bool init(const boost::program_options::variables_map &vm)
Definition cryptonote_protocol_handler.inl:191
uint64_t m_sync_old_spans_downloaded
Definition cryptonote_protocol_handler.h:190
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request &arg, const boost::uuids::uuid &source, epee::net_utils::zone zone, relay_method tx_relay)
Definition cryptonote_protocol_handler.inl:2677
bool request_txpool_complement(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2688
void drop_connections(const epee::net_utils::network_address address)
Definition cryptonote_protocol_handler.inl:2831
nodetool::i_p2p_endpoint< connection_context > * m_p2p
Definition cryptonote_protocol_handler.h:174
int handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:992
int try_add_next_blocks(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1344
unsigned int get_max_out_peers(epee::net_utils::zone zone) const
Definition cryptonote_protocol_handler.h:117
bool kick_idle_peers()
Definition cryptonote_protocol_handler.inl:1691
bool update_sync_search()
Definition cryptonote_protocol_handler.inl:1717
int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1790
epee::math_helper::once_a_time_seconds< 8 > m_idle_peer_kicker
Definition cryptonote_protocol_handler.h:182
uint64_t m_sync_download_objects_size
Definition cryptonote_protocol_handler.h:191
block_queue m_block_queue
Definition cryptonote_protocol_handler.h:181
int handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2480
boost::circular_buffer< size_t > m_avg_buffer
Definition cryptonote_protocol_handler.h:205
bool should_download_next_span(cryptonote_connection_context &context, bool standby)
Definition cryptonote_protocol_handler.inl:1821
t_core & m_core
Definition cryptonote_protocol_handler.h:171
size_t get_synchronizing_connections_count()
Definition cryptonote_protocol_handler.inl:2468
size_t skip_unneeded_hashes(cryptonote_connection_context &context, bool check_block_queue) const
Definition cryptonote_protocol_handler.inl:1968
virtual bool relay_block(NOTIFY_NEW_FLUFFY_BLOCK::request &arg, cryptonote_connection_context &exclude_context)
Definition cryptonote_protocol_handler.inl:2650
bool is_busy_syncing()
Definition cryptonote_protocol_handler.inl:2792
epee::math_helper::once_a_time_milliseconds< 100 > m_standby_checker
Definition cryptonote_protocol_handler.h:183
bool on_idle()
Definition cryptonote_protocol_handler.inl:1682
int handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:581
bool on_callback(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:226
boost::posix_time::ptime m_sync_start_time
Definition cryptonote_protocol_handler.h:196
bool check_standby_peers()
Definition cryptonote_protocol_handler.inl:1774
std::list< connection_info > get_connections()
Definition cryptonote_protocol_handler.inl:356
uint64_t m_sync_start_height
Definition cryptonote_protocol_handler.h:198
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:567
bool deinit()
Definition cryptonote_protocol_handler.inl:211
std::atomic< uint32_t > m_syncronized_connections_count
Definition cryptonote_protocol_handler.h:175
std::atomic< bool > m_stopping
Definition cryptonote_protocol_handler.h:177
nodetool::p2p_endpoint_stub< connection_context > m_p2p_stub
Definition cryptonote_protocol_handler.h:173
size_t m_block_download_max_size
Definition cryptonote_protocol_handler.h:192
boost::mutex m_sync_lock
Definition cryptonote_protocol_handler.h:180
tools::PerformanceTimer m_add_timer
Definition cryptonote_protocol_handler.h:188
int handle_notify_get_txpool_complement(int command, NOTIFY_GET_TXPOOL_COMPLEMENT::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:860
bool on_connection_synchronized()
Definition cryptonote_protocol_handler.inl:2396
cryptonote_connection_context connection_context
Definition cryptonote_protocol_handler.h:82
void stop()
Definition cryptonote_protocol_handler.inl:2883
int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1044
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans)
Definition cryptonote_protocol_handler.inl:2799
uint64_t m_sync_spans_downloaded
Definition cryptonote_protocol_handler.h:190
bool needs_new_sync_connections(epee::net_utils::zone zone) const
Definition cryptonote_protocol_handler.inl:2774
uint64_t m_sync_bad_spans_downloaded
Definition cryptonote_protocol_handler.h:190
boost::posix_time::ptime m_period_start_time
Definition cryptonote_protocol_handler.h:197
std::atomic< bool > m_synchronized
Definition cryptonote_protocol_handler.h:176
int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:762
void on_connection_close(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2855
bool should_drop_connection(cryptonote_connection_context &context, uint32_t next_stripe)
Definition cryptonote_protocol_handler.inl:1906
tools::PerformanceTimer m_sync_timer
Definition cryptonote_protocol_handler.h:188
void log_connections()
Definition cryptonote_protocol_handler.inl:291
Definition cryptonote_basic.h:307
crypto::hash prunable_hash
Definition cryptonote_basic.h:320
Definition byte_slice.h:69
Provides space for levin (p2p) header, so that payload can be sent without copy.
Definition levin_base.h:132
byte_stream buffer
Has space for levin header until a finalize method is used.
Definition levin_base.h:159
Definition net_utils_base.h:70
static constexpr address_type get_type_id() noexcept
Definition net_utils_base.h:93
constexpr uint16_t port() const noexcept
Definition net_utils_base.h:88
Definition net_utils_base.h:173
static constexpr address_type get_type_id() noexcept
Definition net_utils_base.h:199
uint16_t port() const noexcept
Definition net_utils_base.h:194
Definition net_utils_base.h:229
bool is_loopback() const
Definition net_utils_base.h:318
std::string str() const
Definition net_utils_base.h:316
address_type get_type_id() const
Definition net_utils_base.h:320
bool is_same_host(const network_address &other) const
Definition net_utils_base.cpp:120
bool is_local() const
Definition net_utils_base.h:319
std::string host_str() const
Definition net_utils_base.h:317
zone get_zone() const
Definition net_utils_base.h:321
const Type & as() const
Definition net_utils_base.h:324
#define DIFFICULTY_TARGET_V1
Definition cryptonote_config.h:81
#define HASH_OF_HASHES_STEP
Definition cryptonote_config.h:199
#define P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT
Definition cryptonote_config.h:151
#define HF_VERSION_SMALLER_BP
Definition cryptonote_config.h:181
#define CRYPTONOTE_PRUNING_LOG_STRIPES
Definition cryptonote_config.h:207
#define DIFFICULTY_TARGET_V2
Definition cryptonote_config.h:80
#define CRYPTONOTE_MAX_BLOCK_NUMBER
Definition cryptonote_config.h:40
#define P2P_IP_FAILS_BEFORE_BLOCK
Definition cryptonote_config.h:157
#define BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT
Definition cryptonote_config.h:97
@ HAVE_BLOCK_MAIN_CHAIN
Definition cryptonote_core.h:57
@ HAVE_BLOCK_INVALID
Definition cryptonote_core.h:57
@ HAVE_BLOCK_ALT_CHAIN
Definition cryptonote_core.h:57
#define CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT
Definition cryptonote_protocol_handler.h:57
#define IDLE_PEER_KICK_TIME
Definition cryptonote_protocol_handler.inl:74
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY
Definition cryptonote_protocol_handler.inl:72
#define DROP_ON_SYNC_WEDGE_THRESHOLD
Definition cryptonote_protocol_handler.inl:77
#define DROP_PEERS_ON_SCORE
Definition cryptonote_protocol_handler.inl:79
#define MLOG_PEER_STATE(x)
Definition cryptonote_protocol_handler.inl:66
#define MLOG_P2P_MESSAGE(x)
Definition cryptonote_protocol_handler.inl:52
#define REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD
Definition cryptonote_protocol_handler.inl:73
#define NON_RESPONSIVE_PEER_KICK_TIME
Definition cryptonote_protocol_handler.inl:75
#define MLOGIF_P2P_MESSAGE(init, test, x)
Definition cryptonote_protocol_handler.inl:53
#define BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS
Definition cryptonote_protocol_handler.inl:71
#define BLOCK_QUEUE_SIZE_THRESHOLD
Definition cryptonote_protocol_handler.inl:70
#define BLOCK_QUEUE_NSPANS_THRESHOLD
Definition cryptonote_protocol_handler.inl:69
#define ELPP
Definition easylogging++.h:2795
conn start()
#define true
#define false
#define LEVIN_ERROR_CONNECTION
Definition levin_base.h:103
Definition block_weight.py:1
Definition blocks.cpp:13
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Definition command_line.h:269
POD_CLASS hash
Definition hash.h:49
Holds cryptonote related classes and helpers.
Definition blockchain_db.cpp:45
const command_line::arg_descriptor< bool > arg_sync_pruned_blocks
Definition cryptonote_core.cpp:128
boost::multiprecision::uint128_t difficulty_type
Definition difficulty.h:41
network_type
Definition cryptonote_config.h:302
@ TESTNET
Definition cryptonote_config.h:304
@ MAINNET
Definition cryptonote_config.h:303
bool get_pruned_transaction_hash(const transaction &t, const crypto::hash &pruned_data_hash, crypto::hash &res)
Definition cryptonote_format_utils.cpp:1345
relay_method
Methods tracking how a tx was received and relayed.
Definition enums.h:37
@ block
Received in block, takes precedence over others.
Definition enums.h:43
@ none
Received via RPC with do_not_relay set.
Definition enums.h:38
@ forward
Received over i2p/tor; timer delayed before ipv4/6 public broadcast.
Definition enums.h:40
@ fluff
Received/sent over network using Dandelion++ fluff.
Definition enums.h:42
@ stem
Received/send over network using Dandelion++ stem.
Definition enums.h:41
@ local
Received via RPC; trying to send over i2p/tor, etc.
Definition enums.h:39
bool get_block_hash(const block &b, crypto::hash &res)
Definition cryptonote_format_utils.cpp:1523
uint64_t get_block_height(const block &b)
Definition cryptonote_format_utils.cpp:863
bool make_full_pool_supplement_from_block_entry(const cryptonote::block_complete_entry &blk_entry, cryptonote::pool_supplement &pool_supplement)
Definition cryptonote_protocol_handler.inl:140
bool parse_and_validate_tx_base_from_blob(const blobdata_ref &tx_blob, transaction &tx, const bool max_size_check, const bool require_eof)
Definition cryptonote_format_utils.cpp:243
blobdata block_to_blob(const block &b)
Definition cryptonote_format_utils.cpp:1595
bool parse_and_validate_tx_from_blob(const blobdata_ref &tx_blob, transaction &tx, const bool max_size_check)
Definition cryptonote_format_utils.cpp:231
std::string get_protocol_state_string(cryptonote_connection_context::state s)
Definition connection_context.h:123
void get_blob_hash(const blobdata_ref &blob, crypto::hash &res)
Definition cryptonote_format_utils.cpp:1132
bool make_pool_supplement_from_block_entry(const std::vector< cryptonote::tx_blob_entry > &tx_entries, const CryptoHashContainer &blk_tx_hashes, const bool allow_pruned, cryptonote::pool_supplement &pool_supplement)
Definition cryptonote_protocol_handler.inl:84
const command_line::arg_descriptor< size_t > arg_block_download_max_size
Definition cryptonote_core.cpp:123
char get_protocol_state_char(cryptonote_connection_context::state s)
Definition connection_context.h:142
bool parse_and_validate_block_from_blob(const blobdata_ref &b_blob, block &b, crypto::hash *block_hash)
Definition cryptonote_format_utils.cpp:1569
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
Definition cryptonote_format_utils.h:166
@ Info
Mainly useful to represent current progress of application.
Definition easylogging++.h:607
@ Debug
Informational events most useful for developers to debug application.
Definition easylogging++.h:597
@ Yellow
Definition easylogging++.h:615
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
Definition misc_language.h:80
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
Definition misc_language.h:97
const char * zone_to_string(zone value) noexcept
Definition net_utils_base.cpp:165
zone
Definition enums.h:50
@ public_
Definition enums.h:52
@ invalid
Definition enums.h:51
std::string print_connection_context_short(const connection_context_base &ctx)
Definition net_utils_base.cpp:158
bool store_t_to_binary(t_struct &str_in, byte_slice &binary_buff, size_t initial_buffer_size=8192)
Definition portable_storage_template_helper.h:118
std::string pod_to_hex(const t_pod_type &s)
Definition string_tools.h:89
std::string to_string_hex(const T &val)
Definition string_tools.h:118
std::string buff_to_hex_nodelimer(const std::string &src)
Definition string_tools.h:52
uint64_t peerid_type
Definition p2p_protocol_defs.h:49
Definition p2p.py:1
std::string get_human_readable_timespan(uint64_t seconds)
Definition util.cpp:1104
uint64_t ticks_to_ns(uint64_t ticks)
Definition perf_timer.cpp:78
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks)
Definition util.cpp:1332
constexpr uint32_t get_pruning_log_stripes(uint32_t pruning_seed)
Definition pruning.h:41
uint64_t get_tick_count()
Definition perf_timer.cpp:45
uint32_t get_pruning_stripe(uint64_t block_height, uint64_t blockchain_height, uint32_t log_stripes)
Definition pruning.cpp:55
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash)
Creates a SHA-256 digest of a data buffer.
Definition util.cpp:972
bool has_unpruned_block(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:45
#define LOG_ERROR_CCONTEXT(message)
Definition net_utils_base.h:490
#define LOG_DEBUG_CC(ct, message)
Definition net_utils_base.h:476
#define LOG_PRINT_CCONTEXT_L1(message)
Definition net_utils_base.h:487
#define LOG_PRINT_CCONTEXT_L0(message)
Definition net_utils_base.h:486
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message)
Definition net_utils_base.h:492
#define LOG_PRINT_CCONTEXT_L2(message)
Definition net_utils_base.h:488
implementaion for throttling of connection (count and rate-limit speed etc)
const CharType(& source)[N]
Definition pointer.h:1147
#define TIME_MEASURE_FINISH(var_name)
Definition profile_tools.h:64
#define TIME_MEASURE_START(var_name)
Definition profile_tools.h:61
if(!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
Definition signature.cpp:53
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
Definition cryptonote_protocol_defs.h:251
uint64_t cumulative_difficulty_top64
Definition cryptonote_protocol_defs.h:254
uint32_t pruning_seed
Definition cryptonote_protocol_defs.h:257
uint64_t cumulative_difficulty
Definition cryptonote_protocol_defs.h:253
uint8_t top_version
Definition cryptonote_protocol_defs.h:256
uint64_t current_height
Definition cryptonote_protocol_defs.h:252
crypto::hash top_id
Definition cryptonote_protocol_defs.h:255
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:376
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:186
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:336
static const int ID
Definition cryptonote_protocol_defs.h:324
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:208
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:286
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:358
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:227
static const int ID
Definition cryptonote_protocol_defs.h:291
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:316
epee::misc_utils::struct_init< request_t > request
Definition cryptonote_protocol_defs.h:246
static const int ID
Definition cryptonote_protocol_defs.h:232
Definition cryptonote_protocol_defs.h:133
uint64_t block_weight
Definition cryptonote_protocol_defs.h:136
std::vector< tx_blob_entry > txs
Definition cryptonote_protocol_defs.h:137
bool pruned
Definition cryptonote_protocol_defs.h:134
blobdata block
Definition cryptonote_protocol_defs.h:135
crypto::hash prev_id
Definition cryptonote_basic.h:564
Definition verification_context.h:66
bool m_verifivation_failed
Definition verification_context.h:68
bool m_bad_pow
Definition verification_context.h:72
bool m_added_to_main_chain
Definition verification_context.h:67
bool m_already_exists
Definition verification_context.h:70
bool m_marked_as_orphaned
Definition verification_context.h:69
bool m_missing_txs
Definition verification_context.h:73
Definition cryptonote_basic.h:577
std::vector< crypto::hash > tx_hashes
Definition cryptonote_basic.h:592
Definition cryptonote_protocol_defs.h:48
std::string connection_id
Definition cryptonote_protocol_defs.h:81
uint32_t pruning_seed
Definition cryptonote_protocol_defs.h:85
std::string address
Definition cryptonote_protocol_defs.h:54
uint8_t address_type
Definition cryptonote_protocol_defs.h:87
uint64_t recv_count
Definition cryptonote_protocol_defs.h:63
uint64_t live_time
Definition cryptonote_protocol_defs.h:71
uint32_t support_flags
Definition cryptonote_protocol_defs.h:79
uint32_t rpc_credits_per_hash
Definition cryptonote_protocol_defs.h:59
bool localhost
Definition cryptonote_protocol_defs.h:50
std::string port
Definition cryptonote_protocol_defs.h:57
uint64_t height
Definition cryptonote_protocol_defs.h:83
uint64_t send_idle_time
Definition cryptonote_protocol_defs.h:67
std::string host
Definition cryptonote_protocol_defs.h:55
std::string ip
Definition cryptonote_protocol_defs.h:56
uint64_t current_download
Definition cryptonote_protocol_defs.h:74
uint64_t avg_download
Definition cryptonote_protocol_defs.h:73
uint64_t recv_idle_time
Definition cryptonote_protocol_defs.h:64
uint16_t rpc_port
Definition cryptonote_protocol_defs.h:58
uint64_t send_count
Definition cryptonote_protocol_defs.h:66
std::string state
Definition cryptonote_protocol_defs.h:69
bool local_ip
Definition cryptonote_protocol_defs.h:51
bool ssl
Definition cryptonote_protocol_defs.h:52
bool incoming
Definition cryptonote_protocol_defs.h:49
std::string peer_id
Definition cryptonote_protocol_defs.h:61
uint64_t current_upload
Definition cryptonote_protocol_defs.h:77
uint64_t avg_upload
Definition cryptonote_protocol_defs.h:76
Definition connection_context.h:44
@ state_before_handshake
Definition connection_context.h:52
@ state_normal
Definition connection_context.h:56
@ state_standby
Definition connection_context.h:54
@ state_synchronizing
Definition connection_context.h:53
uint32_t m_rpc_credits_per_hash
Definition connection_context.h:113
uint16_t m_rpc_port
Definition connection_context.h:112
uint64_t m_remote_blockchain_height
Definition connection_context.h:105
uint32_t m_pruning_seed
Definition connection_context.h:111
boost::posix_time::ptime m_last_request_time
Definition connection_context.h:108
state m_state
Definition connection_context.h:101
Used to provide transaction info that skips the mempool to block handling code.
Definition tx_verification_utils.h:101
std::uint8_t nic_verified_hf_version
Definition tx_verification_utils.h:107
std::unordered_map< crypto::hash, std::pair< transaction, blobdata > > txs_by_txid
Definition tx_verification_utils.h:104
Definition cryptonote_protocol_defs.h:122
crypto::hash prunable_hash
Definition cryptonote_protocol_defs.h:124
Definition verification_context.h:41
relay_method m_relay
Definition verification_context.h:44
bool m_no_drop_offense
Definition verification_context.h:50
Definition cryptonote_basic.h:106
time_t m_last_send
Definition net_utils_base.h:378
time_t m_last_recv
Definition net_utils_base.h:377
uint64_t m_send_cnt
Definition net_utils_base.h:380
const bool m_is_income
Definition net_utils_base.h:374
const bool m_ssl
Definition net_utils_base.h:376
const boost::uuids::uuid m_connection_id
Definition net_utils_base.h:372
const time_t m_started
Definition net_utils_base.h:375
const network_address m_remote_address
Definition net_utils_base.h:373
double m_current_speed_down
Definition net_utils_base.h:381
double m_current_speed_up
Definition net_utils_base.h:382
uint64_t m_recv_cnt
Definition net_utils_base.h:379
Definition net_node_common.h:53
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:153
std::string data
Definition base58.cpp:37
struct hash_func hashes[]
randomx_vm * vm
Definition tests.cpp:20
cryptonote::transaction tx
Definition transaction.cpp:40