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 if (tx_entry.blob.size() > get_max_tx_size())
101 {
102 MERROR("Transaction blob of length " << tx_entry.blob.size() << " is too large to unpack!");
103 return false;
104 }
105
106 const bool is_pruned = tx_entry.prunable_hash != crypto::null_hash;
107 if (is_pruned && !allow_pruned)
108 {
109 MERROR("Pruned transaction not allowed here");
110 return false;
111 }
112
114 crypto::hash tx_hash;
115 bool parse_success = false;
116 if (is_pruned)
117 {
118 if ((parse_success = cryptonote::parse_and_validate_tx_base_from_blob(tx_entry.blob, tx)))
119 parse_success = cryptonote::get_pruned_transaction_hash(tx, tx_entry.prunable_hash, tx_hash);
120 }
121 else
122 {
123 parse_success = cryptonote::parse_and_validate_tx_from_blob(tx_entry.blob, tx, tx_hash);
124 }
125
126 if (!parse_success)
127 {
128 MERROR("failed to parse and/or validate transaction: "
130 );
131 return false;
132 }
133 else if (!blk_tx_hashes.count(tx_hash))
134 {
135 MERROR("transaction " << tx_hash << " not in block");
136 return false;
137 }
138
139 pool_supplement.txs_by_txid.emplace(tx_hash, std::make_pair(std::move(tx), tx_entry.blob));
140 }
141
142 return true;
143 }
144
146 const cryptonote::block_complete_entry& blk_entry,
148 {
151 {
152 MERROR("sent bad block: failed to parse and/or validate block: "
154 );
155 return false;
156 }
157
158 const std::unordered_set<crypto::hash> blk_tx_hashes(blk.tx_hashes.cbegin(), blk.tx_hashes.cend());
159
160 if (blk_tx_hashes.size() != blk_entry.txs.size())
161 {
162 MERROR("sent bad block entry: number of hashes is not equal number of tx blobs: "
164 );
165 return false;
166 }
167 else if (blk_tx_hashes.size() != blk.tx_hashes.size())
168 {
169 MERROR("sent bad block entry: there are duplicate tx hashes in parsed block: "
171 return false;
172 }
173
174 // We set `allow_pruned` equal to whether this block entry is pruned since the pruned flag
175 // should be checked anyways by the time we deserialize transactions
176 return make_pool_supplement_from_block_entry(blk_entry.txs, blk_tx_hashes, blk_entry.pruned, pool_supplement);
177 }
178
179
180 //-----------------------------------------------------------------------------------------------------------------------
181 template<class t_core>
194 //-----------------------------------------------------------------------------------------------------------------------
195 template<class t_core>
214 //------------------------------------------------------------------------------------------------------------------------
215 template<class t_core>
217 {
218 return true;
219 }
220 //------------------------------------------------------------------------------------------------------------------------
221 template<class t_core>
229 //------------------------------------------------------------------------------------------------------------------------
230 template<class t_core>
232 {
233 LOG_PRINT_CCONTEXT_L2("callback fired");
234 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);
235 --context.m_callback_request_count;
236
237 uint32_t notified = true;
238 if (context.m_idle_peer_notification.compare_exchange_strong(notified, not notified))
239 {
240 if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
241 {
242 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
243 const boost::posix_time::time_duration dt = now - context.m_last_request_time;
244 const auto ms = dt.total_microseconds();
245 if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
246 {
247 if (context.m_score-- >= 0)
248 {
249 MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
250 context.m_last_request_time = boost::date_time::not_a_date_time;
251 context.m_expect_response = 0;
252 context.m_expect_height = 0;
253 context.m_requested_objects.clear();
254 context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
255 }
256 else
257 {
258 MINFO(context << "dropping idle peer with negative score");
259 drop_connection_with_score(context, context.m_expect_response == 0 ? 1 : 5, false);
260 return false;
261 }
262 }
263 }
264 }
265
266 notified = true;
267 if (context.m_new_stripe_notification.compare_exchange_strong(notified, not notified))
268 {
269 if (context.m_state == cryptonote_connection_context::state_normal)
271 }
272
273 if(context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time == boost::posix_time::not_a_date_time)
274 {
276 context.m_needed_objects.clear();
277 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
278 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
279 r.prune = m_sync_pruned_blocks;
280 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
281 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
282 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
284 MLOG_PEER_STATE("requesting chain");
285 }
286 else if(context.m_state == cryptonote_connection_context::state_standby)
287 {
289 try_add_next_blocks(context);
290 }
291
292 return true;
293 }
294 //------------------------------------------------------------------------------------------------------------------------
295 template<class t_core>
297 {
298 std::stringstream ss;
299 ss.precision(1);
300
301 double down_sum = 0.0;
302 double down_curr_sum = 0.0;
303 double up_sum = 0.0;
304 double up_curr_sum = 0.0;
305
306 ss << std::setw(30) << std::left << "Remote Host"
307 << std::setw(20) << "Peer id"
308 << std::setw(20) << "Support Flags"
309 << std::setw(30) << "Recv/Sent (inactive,sec)"
310 << std::setw(25) << "State"
311 << std::setw(20) << "Livetime(sec)"
312 << std::setw(12) << "Down (kB/s)"
313 << std::setw(14) << "Down(now)"
314 << std::setw(10) << "Up (kB/s)"
315 << std::setw(13) << "Up(now)"
316 << ENDL;
317
318 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
319 {
320 bool local_ip = cntxt.m_remote_address.is_local();
321 auto connection_time = time(NULL) - cntxt.m_started;
322 ss << std::setw(30) << std::left << std::string(cntxt.m_is_income ? " [INC]":"[OUT]") +
323 cntxt.m_remote_address.str()
324 << std::setw(20) << nodetool::peerid_to_string(peer_id)
325 << std::setw(20) << std::hex << support_flags
326 << 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) + ")"
327 << std::setw(25) << get_protocol_state_string(cntxt.m_state)
328 << std::setw(20) << std::to_string(time(NULL) - cntxt.m_started)
329 << std::setw(12) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_recv_cnt / connection_time / 1024)
330 << std::setw(14) << std::fixed << cntxt.m_current_speed_down / 1024
331 << std::setw(10) << std::fixed << (connection_time == 0 ? 0.0 : cntxt.m_send_cnt / connection_time / 1024)
332 << std::setw(13) << std::fixed << cntxt.m_current_speed_up / 1024
333 << (local_ip ? "[LAN]" : "")
334 << std::left << (cntxt.m_remote_address.is_loopback() ? "[LOCALHOST]" : "") // 127.0.0.1
335 << ENDL;
336
337 if (connection_time > 1)
338 {
339 down_sum += (cntxt.m_recv_cnt / connection_time / 1024);
340 up_sum += (cntxt.m_send_cnt / connection_time / 1024);
341 }
342
343 down_curr_sum += (cntxt.m_current_speed_down / 1024);
344 up_curr_sum += (cntxt.m_current_speed_up / 1024);
345
346 return true;
347 });
348 ss << ENDL
349 << std::setw(125) << " "
350 << std::setw(12) << down_sum
351 << std::setw(14) << down_curr_sum
352 << std::setw(10) << up_sum
353 << std::setw(13) << up_curr_sum
354 << ENDL;
355 LOG_PRINT_L0("Connections: " << ENDL << ss.str());
356 }
357 //------------------------------------------------------------------------------------------------------------------------
358 // Returns a list of connection_info objects describing each open p2p connection
359 //------------------------------------------------------------------------------------------------------------------------
360 template<class t_core>
362 {
363 std::list<connection_info> connections;
364
365 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags)
366 {
367 connection_info cnx;
368 auto timestamp = time(NULL);
369
370 cnx.incoming = cntxt.m_is_income ? true : false;
371
372 cnx.address = cntxt.m_remote_address.str();
373 cnx.host = cntxt.m_remote_address.host_str();
374 cnx.ip = "";
375 cnx.port = "";
377 {
378 cnx.ip = cnx.host;
379 cnx.port = std::to_string(cntxt.m_remote_address.as<epee::net_utils::ipv4_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);
596 return 1;
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);
612 return 1;
613 }
614
615 // Log block info
616 MLOG_P2P_MESSAGE(context << "Received NOTIFY_NEW_FLUFFY_BLOCK " << new_block_hash << " (height "
617 << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
618
619 // Pause mining and resume after block verification to prevent wasted mining cycles while
620 // validating the next block. Needs more research into if this is a DoS vector or not. Invalid
621 // block validation will cause disconnects and bans, so it might not be that bad.
622 m_core.pause_mine();
623 const auto resume_mine_on_leave = epee::misc_utils::create_scope_leave_handler([this](){ m_core.resume_mine(); });
624
625 // This set allows us to quickly sanity check that the block binds all txs contained in this
626 // fluffy payload, which means that no extra stowaway txs can be harbored. In the case of a
627 // deterministic block verification failure, the peer will be punished accordingly. For other
628 // cases, *once* valid PoW will be required to perform expensive consensus checks for the txs
629 // inside the block.
630 std::unordered_map<crypto::hash, uint64_t> blk_txids_set;
631 for (size_t tx_idx = 0; tx_idx < new_block.tx_hashes.size(); ++tx_idx)
632 blk_txids_set.emplace(new_block.tx_hashes[tx_idx], tx_idx);
633
634 // Check for duplicate txids in parsed block blob
635 if (blk_txids_set.size() != new_block.tx_hashes.size())
636 {
637 MERROR("sent bad block entry: there are duplicate tx hashes in parsed block: "
639 drop_connection(context, false, false);
640 return 1;
641 }
642
643 // Keeping a map of the full transactions provided in this payload allows us to pass them
644 // directly to core::handle_single_incoming_block() -> Blockchain::add_block(), which means we
645 // can skip the mempool for faster block propagation. Later in the function, we will erase all
646 // transactions from the relayed block.
647 pool_supplement extra_block_txs;
648 if (!make_pool_supplement_from_block_entry(arg.b.txs, blk_txids_set, /*allow_pruned=*/false, extra_block_txs))
649 {
651 (
652 "Failed to parse one or more transactions in fluffy block with ID " << new_block_hash <<
653 ", dropping connection"
654 );
655
656 drop_connection(context, false, false);
657 return 1;
658 }
659
660 // try adding block to the blockchain
662 const bool handle_block_res = m_core.handle_single_incoming_block(arg.b.block,
663 &new_block,
664 bvc,
665 extra_block_txs);
666
667 // handle result of attempted block add
668 if (!handle_block_res || bvc.m_verifivation_failed)
669 {
670 if (bvc.m_missing_txs)
671 {
672 // Block verification failed b/c of missing transactions, so request fluffy block again with
673 // missing transactions (including the ones newly discovered in this fluffy block). Note that
674 // PoW checking happens before missing transactions checks, so if bvc.m_missing_txs is true,
675 // then that means that we passed PoW checking, so a peer can't get us to re-request fluffy
676 // blocks for free.
677
678 // Instead of requesting missing transactions by hash like BTC,
679 // we do it by index (thanks to a suggestion from moneromooo) because
680 // we're way cooler .. and also because they're smaller than hashes.
681 std::vector<uint64_t> need_tx_indices;
682 need_tx_indices.reserve(new_block.tx_hashes.size());
683
684 // Collect need_tx_indices by polling blockchain storage and mempool storage
685 for (size_t tx_idx = 0; tx_idx < new_block.tx_hashes.size(); ++tx_idx)
686 {
687 const crypto::hash &tx_hash = new_block.tx_hashes[tx_idx];
688
689 std::vector<cryptonote::blobdata> tx_blobs;
690 std::vector<crypto::hash> missed_txs;
691
692 bool need_tx = !m_core.pool_has_tx(tx_hash);
693 need_tx = need_tx && (!m_core.get_transactions({tx_hash}, tx_blobs, missed_txs, /*pruned=*/true)
694 || !missed_txs.empty());
695
696 if (need_tx)
697 need_tx_indices.push_back(tx_idx);
698 }
699
700 // Make request form
701 MDEBUG("We are missing " << need_tx_indices.size() << " txes for this fluffy block");
702 for (auto txidx: need_tx_indices)
703 MDEBUG(" tx " << new_block.tx_hashes[txidx]);
705 missing_tx_req.block_hash = new_block_hash;
706 missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
707 missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
708
709 // Post NOTIFY_REQUEST_FLUFFY_MISSING_TX request to peer
710 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_FLUFFY_MISSING_TX: missing_tx_indices.size()=" << missing_tx_req.missing_tx_indices.size() );
711 post_notify<NOTIFY_REQUEST_FLUFFY_MISSING_TX>(missing_tx_req, context);
712 }
713 else // failure for some other reason besides missing txs...
714 {
715 // drop connection and punish peer
716 LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection");
718 return 1;
719 }
720 }
721 else if( bvc.m_added_to_main_chain )
722 {
723 // Relay an empty block
724 arg.b.txs.clear();
725 relay_block(arg, context);
726 }
727 else if( bvc.m_marked_as_orphaned )
728 {
729 context.m_needed_objects.clear();
732 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
733 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
734 r.prune = m_sync_pruned_blocks;
735 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
736 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
737 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
739 MLOG_PEER_STATE("requesting chain");
740 }
741
742 // load json & DNS checkpoints every 10min/hour respectively,
743 // and verify them with respect to what blocks we already have
744 CHECK_AND_ASSERT_MES(m_core.update_checkpoints(), 1, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
745
746 return 1;
747 }
748 //------------------------------------------------------------------------------------------------------------------------
749 template<class t_core>
751 {
752 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_FLUFFY_MISSING_TX (" << arg.missing_tx_indices.size() << " txes), block hash " << arg.block_hash);
754 {
755 LOG_ERROR_CCONTEXT("Requested fluffy tx before handshake, dropping connection");
756 drop_connection(context, false, false);
757 return 1;
758 }
759
760 std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
761 std::vector<cryptonote::blobdata> local_txs;
762
763 block b;
764 if (!m_core.get_block_by_hash(arg.block_hash, b))
765 {
766 LOG_ERROR_CCONTEXT("failed to find block: " << arg.block_hash << ", dropping connection");
767 drop_connection(context, false, false);
768 return 1;
769 }
770
771 std::vector<crypto::hash> txids;
772 txids.reserve(b.tx_hashes.size());
773 NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
774 fluffy_response.b.block = t_serializable_object_to_blob(b);
775 fluffy_response.current_blockchain_height = arg.current_blockchain_height;
776 std::vector<bool> seen(b.tx_hashes.size(), false);
777 for(auto& tx_idx: arg.missing_tx_indices)
778 {
779 if(tx_idx < b.tx_hashes.size())
780 {
781 MDEBUG(" tx " << b.tx_hashes[tx_idx]);
782 if (seen[tx_idx])
783 {
785 (
786 "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
787 << ", request is asking for duplicate tx "
788 << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
789 << ", block_height = " << arg.current_blockchain_height
790 << ", dropping connection"
791 );
792 drop_connection(context, true, false);
793 return 1;
794 }
795 txids.push_back(b.tx_hashes[tx_idx]);
796 seen[tx_idx] = true;
797 }
798 else
799 {
801 (
802 "Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX"
803 << ", request is asking for a tx whose index is out of bounds "
804 << ", tx index = " << tx_idx << ", block tx count " << b.tx_hashes.size()
805 << ", block_height = " << arg.current_blockchain_height
806 << ", dropping connection"
807 );
808
809 drop_connection(context, false, false);
810 return 1;
811 }
812 }
813
814 std::vector<cryptonote::transaction> txs;
815 std::vector<crypto::hash> missed;
816 if (!m_core.get_transactions(txids, txs, missed))
817 {
818 LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
819 << "failed to get requested transactions");
820 drop_connection(context, false, false);
821 return 1;
822 }
823 if (!missed.empty() || txs.size() != txids.size())
824 {
825 LOG_ERROR_CCONTEXT("Failed to handle request NOTIFY_REQUEST_FLUFFY_MISSING_TX, "
826 << missed.size() << " requested transactions not found" << ", dropping connection");
827 drop_connection(context, false, false);
828 return 1;
829 }
830
831 for(auto& tx: txs)
832 {
833 fluffy_response.b.txs.push_back({t_serializable_object_to_blob(tx), crypto::null_hash});
834 }
835
837 (
838 "-->>NOTIFY_RESPONSE_FLUFFY_MISSING_TX: "
839 << ", txs.size()=" << fluffy_response.b.txs.size()
840 << ", rsp.current_blockchain_height=" << fluffy_response.current_blockchain_height
841 );
842
843 post_notify<NOTIFY_NEW_FLUFFY_BLOCK>(fluffy_response, context);
844 return 1;
845 }
846 //------------------------------------------------------------------------------------------------------------------------
847 template<class t_core>
849 {
850 MLOG_P2P_MESSAGE("Received NOTIFY_GET_TXPOOL_COMPLEMENT (" << arg.hashes.size() << " txes)");
852 return 1;
853
854 std::vector<std::pair<cryptonote::blobdata, block>> local_blocks;
855 std::vector<cryptonote::blobdata> local_txs;
856
857 std::vector<cryptonote::blobdata> txes;
858 if (!m_core.get_txpool_complement(std::move(arg.hashes), txes))
859 {
860 LOG_ERROR_CCONTEXT("failed to get txpool complement");
861 return 1;
862 }
863
865 new_txes.txs = std::move(txes);
866
868 (
869 "-->>NOTIFY_NEW_TRANSACTIONS: "
870 << ", txs.size()=" << new_txes.txs.size()
871 );
872
873 post_notify<NOTIFY_NEW_TRANSACTIONS>(new_txes, context);
874 return 1;
875 }
876 //------------------------------------------------------------------------------------------------------------------------
877 template<class t_core>
879 {
880 MLOG_P2P_MESSAGE("Received NOTIFY_NEW_TRANSACTIONS (" << arg.txs.size() << " txes)");
881 std::unordered_set<blobdata> seen;
882 for (const auto &blob: arg.txs)
883 {
884 MLOGIF_P2P_MESSAGE(cryptonote::transaction tx; crypto::hash hash; bool ret = cryptonote::parse_and_validate_tx_from_blob(blob, tx, hash);, ret, "Including transaction " << hash);
885 if (seen.find(blob) != seen.end())
886 {
887 LOG_PRINT_CCONTEXT_L1("Duplicate transaction in notification, dropping connection");
888 drop_connection(context, false, false);
889 return 1;
890 }
891 seen.insert(blob);
892 }
893
895 return 1;
896
897 // while syncing, core will lock for a long time, so we ignore
898 // those txes as they aren't really needed anyway, and avoid a
899 // long block before replying
900 if(!is_synchronized())
901 {
902 LOG_DEBUG_CC(context, "Received new tx while syncing, ignored");
903 return 1;
904 }
905
906 /* If the txes were received over i2p/tor, the default is to "forward"
907 with a randomized delay to further enhance the "white noise" behavior,
908 potentially making it harder for ISP-level spies to determine which
909 inbound link sent the tx. If the sender disabled "white noise" over
910 i2p/tor, then the sender is "fluffing" (to only outbound) i2p/tor
911 connections with the `dandelionpp_fluff` flag set. The receiver (hidden
912 service) will immediately fluff in that scenario (i.e. this assumes that a
913 sybil spy will be unable to link an IP to an i2p/tor connection). */
914
915 const epee::net_utils::zone zone = context.m_remote_address.get_zone();
918
919 std::vector<blobdata> stem_txs{};
920 std::vector<blobdata> fluff_txs{};
921 if (arg.dandelionpp_fluff)
922 {
923 tx_relay = relay_method::fluff;
924 fluff_txs.reserve(arg.txs.size());
925 }
926 else
927 stem_txs.reserve(arg.txs.size());
928
929 for (auto& tx : arg.txs)
930 {
932 if (!m_core.handle_incoming_tx(tx, tvc, tx_relay, true) && !tvc.m_no_drop_offense)
933 {
934 LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
935 drop_connection(context, false, false);
936 return 1;
937 }
938
939 switch (tvc.m_relay)
940 {
943 stem_txs.push_back(std::move(tx));
944 break;
947 fluff_txs.push_back(std::move(tx));
948 break;
949 default:
950 case relay_method::forward: // not supposed to happen here
952 break;
953 }
954 }
955
956 if (!stem_txs.empty())
957 {
958 //TODO: add announce usage here
959 arg.dandelionpp_fluff = false;
960 arg.txs = std::move(stem_txs);
961 relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone(), relay_method::stem);
962 }
963 if (!fluff_txs.empty())
964 {
965 //TODO: add announce usage here
966 arg.dandelionpp_fluff = true;
967 arg.txs = std::move(fluff_txs);
968 relay_transactions(arg, context.m_connection_id, context.m_remote_address.get_zone(), relay_method::fluff);
969 }
970 return 1;
971 }
972 //------------------------------------------------------------------------------------------------------------------------
973 template<class t_core>
975 {
977 {
978 LOG_ERROR_CCONTEXT("Requested objects before handshake, dropping connection");
979 drop_connection(context, false, false);
980 return 1;
981 }
982 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
983 if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_OBJECT_REQUEST_COUNT)
984 {
986 "Requested objects count is too big ("
987 << arg.blocks.size() << ") expected not more then "
989 drop_connection(context, false, false);
990 return 1;
991 }
992
994 if(!m_core.handle_get_objects(arg, rsp, context))
995 {
996 LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection");
997 drop_connection(context, false, false);
998 return 1;
999 }
1000 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
1001 MLOG_P2P_MESSAGE("-->>NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()="
1002 << rsp.blocks.size() << ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height
1003 << ", missed_ids.size()=" << rsp.missed_ids.size());
1005 //handler_response_blocks_now(sizeof(rsp)); // XXX
1006 //handler_response_blocks_now(200);
1007 return 1;
1008 }
1009 //------------------------------------------------------------------------------------------------------------------------
1010
1011
1012 template<class t_core>
1014 {
1016 if (m_avg_buffer.empty()) {
1017 MWARNING("m_avg_buffer.size() == 0");
1018 return 500;
1019 }
1020 double avg = 0;
1021 for (const auto &element : m_avg_buffer) avg += element;
1022 return avg / m_avg_buffer.size();
1023 }
1024
1025 template<class t_core>
1027 {
1028 MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_GET_OBJECTS (" << arg.blocks.size() << " blocks)");
1029 MLOG_PEER_STATE("received objects");
1030
1031 boost::posix_time::ptime request_time = context.m_last_request_time;
1032 context.m_last_request_time = boost::date_time::not_a_date_time;
1033
1034 if (context.m_expect_response != NOTIFY_RESPONSE_GET_OBJECTS::ID)
1035 {
1036 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_GET_OBJECTS out of the blue, dropping connection");
1037 drop_connection(context, true, false);
1038 return 1;
1039 }
1040 context.m_expect_response = 0;
1041
1042 // calculate size of request
1043 size_t size = 0;
1044 size_t blocks_size = 0;
1045 for (const auto &element : arg.blocks) {
1046 blocks_size += element.block.size();
1047 for (const auto &tx : element.txs)
1048 blocks_size += tx.blob.size();
1049 }
1050 size += blocks_size;
1051
1052 for (const auto &element : arg.missed_ids)
1053 size += sizeof(element.data);
1054
1055 size += sizeof(arg.current_blockchain_height);
1056 {
1058 m_avg_buffer.push_back(size);
1059 }
1062 MDEBUG(context << " downloaded " << size << " bytes worth of blocks");
1063
1064 /*using namespace boost::chrono;
1065 auto point = steady_clock::now();
1066 auto time_from_epoh = point.time_since_epoch();
1067 auto sec = duration_cast< seconds >( time_from_epoh ).count();*/
1068
1069 //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());
1070
1071 if(arg.blocks.empty())
1072 {
1073 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: no blocks");
1074 drop_connection(context, true, false);
1076 return 1;
1077 }
1078 if(context.m_last_response_height > arg.current_blockchain_height)
1079 {
1080 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
1081 << " < m_last_response_height=" << context.m_last_response_height << ", dropping connection");
1082 drop_connection(context, false, false);
1084 return 1;
1085 }
1086
1087 if (arg.current_blockchain_height < context.m_remote_blockchain_height)
1088 {
1089 MINFO(context << "Claims " << arg.current_blockchain_height << ", claimed " << context.m_remote_blockchain_height << " before");
1090 hit_score(context, 1);
1091 }
1092 context.m_remote_blockchain_height = arg.current_blockchain_height;
1093 if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
1094 m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
1095
1096 std::vector<crypto::hash> block_hashes;
1097 block_hashes.reserve(arg.blocks.size());
1098 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1099 uint64_t start_height = std::numeric_limits<uint64_t>::max();
1100 crypto::hash previous{};
1102 for(std::size_t i = 0; i < arg.blocks.size(); ++i)
1103 {
1104 if (m_stopping)
1105 {
1106 return 1;
1107 }
1108
1109 crypto::hash block_hash;
1110 if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash))
1111 {
1112 LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
1113 << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
1114 drop_connection(context, false, false);
1116 return 1;
1117 }
1118 if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
1119 {
1120 LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
1121 << epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
1122 drop_connection(context, false, false);
1124 return 1;
1125 }
1126
1127 const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
1128 if (context.get_expected_hash(this_height) != block_hash)
1129 {
1130 LOG_ERROR_CCONTEXT("Sent invalid chain");
1131 drop_connection(context, false, false);
1133 return 1;
1134 }
1135
1136 // if first block
1137 if (start_height == std::numeric_limits<uint64_t>::max())
1138 {
1139 start_height = this_height;
1140 if (start_height > context.m_expect_height)
1141 {
1142 LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
1143 drop_connection(context, false, false);
1145 return 1;
1146 }
1147
1148 if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id)
1149 {
1150 LOG_ERROR_CCONTEXT("Sent invalid chain");
1151 drop_connection(context, false, false);
1153 return 1;
1154 }
1155 }
1156 else if (b.prev_id != previous)
1157 {
1158 LOG_ERROR_CCONTEXT("Sent invalid chain");
1159 drop_connection(context, false, false);
1161 return 1;
1162 }
1163 previous = block_hash;
1164
1165 if (start_height + i != this_height)
1166 {
1167 LOG_ERROR_CCONTEXT("Sent invalid chain");
1168 drop_connection(context, false, false);
1170 return 1;
1171 }
1172
1173 auto req_it = context.m_requested_objects.find(block_hash);
1174 if(req_it == context.m_requested_objects.end())
1175 {
1176 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))
1177 << " wasn't requested, dropping connection");
1178 drop_connection(context, false, false);
1180 return 1;
1181 }
1182 if(b.tx_hashes.size() != arg.blocks[i].txs.size())
1183 {
1184 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))
1185 << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection");
1186 drop_connection(context, false, false);
1188 return 1;
1189 }
1190
1191 context.m_requested_objects.erase(req_it);
1192 block_hashes.push_back(block_hash);
1193 }
1194
1195 if(!context.m_requested_objects.empty())
1196 {
1197 MERROR(context << "returned not all requested objects (context.m_requested_objects.size()="
1198 << context.m_requested_objects.size() << "), dropping connection");
1199 drop_connection(context, false, false);
1201 return 1;
1202 }
1203
1204 const bool pruned_ok = should_ask_for_pruned_data(context, start_height, arg.blocks.size(), true);
1205 if (!pruned_ok)
1206 {
1207 // if we don't want pruned data, check we did not get any
1208 for (block_complete_entry& block_entry: arg.blocks)
1209 {
1210 if (block_entry.pruned)
1211 {
1212 MERROR(context << "returned a pruned block, dropping connection");
1213 drop_connection(context, false, false);
1215 return 1;
1216 }
1217 if (block_entry.block_weight)
1218 {
1219 MERROR(context << "returned a block weight for a non pruned block, dropping connection");
1220 drop_connection(context, false, false);
1222 return 1;
1223 }
1224 for (const tx_blob_entry &tx_entry: block_entry.txs)
1225 {
1226 if (tx_entry.prunable_hash != crypto::null_hash)
1227 {
1228 MERROR(context << "returned at least one pruned object which we did not expect, dropping connection");
1229 drop_connection(context, false, false);
1231 return 1;
1232 }
1233 }
1234 }
1235 }
1236 else
1237 {
1238 // we accept pruned data, check that if we got some, then no weights are zero
1239 for (block_complete_entry& block_entry: arg.blocks)
1240 {
1241 if (block_entry.block_weight == 0 && block_entry.pruned)
1242 {
1243 MERROR(context << "returned at least one pruned block with 0 weight, dropping connection");
1244 drop_connection(context, false, false);
1246 return 1;
1247 }
1248 }
1249 }
1250
1251 {
1252 MLOG_YELLOW(el::Level::Debug, context << " Got NEW BLOCKS inside of " << __FUNCTION__ << ": size: " << arg.blocks.size()
1253 << ", blocks: " << start_height << " - " << (start_height + arg.blocks.size() - 1) <<
1254 " (pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ")");
1255
1256 // add that new span to the block queue
1257 const boost::posix_time::time_duration dt = now - request_time;
1258 const float rate = size * 1e6 / (dt.total_microseconds() + 1);
1259 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");
1260 m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, context.m_remote_address, rate, blocks_size);
1261
1262 const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
1263 context.m_last_known_hash = last_block_hash;
1264
1265 if (!m_core.get_test_drop_download() || !m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
1266 return 1;
1267 }
1268 }
1269
1270 try_add_next_blocks(context);
1271 return 1;
1272 }
1273
1274 // Get an estimate for the remaining sync time from given current to target blockchain height, in seconds
1275 template<class t_core>
1277 {
1278 // The average sync speed varies so much, even averaged over quite long time periods like 10 minutes,
1279 // that using some sliding window would be difficult to implement without often leading to bad estimates.
1280 // The simplest strategy - always average sync speed over the maximum available interval i.e. since sync
1281 // started at all (from "m_sync_start_time" and "m_sync_start_height") - gives already useful results
1282 // and seems to be quite robust. Some quite special cases like "Internet connection suddenly becoming
1283 // much faster after syncing already a long time, and staying fast" are not well supported however.
1284
1285 if (target_blockchain_height <= current_blockchain_height)
1286 {
1287 // Syncing stuck, or other special circumstance: Avoid errors, simply give back 0
1288 return 0;
1289 }
1290
1291 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1292 const boost::posix_time::time_duration sync_time = now - m_sync_start_time;
1293 cryptonote::network_type nettype = m_core.get_nettype();
1294
1295 // Don't simply use remaining number of blocks for the estimate but "sync weight" as provided by
1296 // "cumulative_block_sync_weight" which knows about strongly varying Monero mainnet block sizes
1297 uint64_t synced_weight = tools::cumulative_block_sync_weight(nettype, m_sync_start_height, current_blockchain_height - m_sync_start_height);
1298 float us_per_weight = (float)sync_time.total_microseconds() / (float)synced_weight;
1299 uint64_t remaining_weight = tools::cumulative_block_sync_weight(nettype, current_blockchain_height, target_blockchain_height - current_blockchain_height);
1300 float remaining_us = us_per_weight * (float)remaining_weight;
1301 return (uint64_t)(remaining_us / 1e6);
1302 }
1303
1304 // Return a textual remaining sync time estimate, or the empty string if waiting period not yet over
1305 template<class t_core>
1306 std::string t_cryptonote_protocol_handler<t_core>::get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
1307 {
1308 std::string text = "";
1309 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1310 boost::posix_time::time_duration period_sync_time = now - m_period_start_time;
1311 if (period_sync_time > boost::posix_time::minutes(2))
1312 {
1313 // Period is over, time to report another estimate
1314 uint64_t remaining_seconds = get_estimated_remaining_sync_seconds(current_blockchain_height, target_blockchain_height);
1315 text = tools::get_human_readable_timespan(remaining_seconds);
1316
1317 // Start the new period
1318 m_period_start_time = now;
1319 }
1320 return text;
1321 }
1322
1323 template<class t_core>
1325 {
1326 bool force_next_span = false;
1327
1328 {
1329 // We try to lock the sync lock. If we can, it means no other thread is
1330 // currently adding blocks, so we do that for as long as we can from the
1331 // block queue. Then, we go back to download.
1332 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
1333 if (!sync.owns_lock())
1334 {
1335 MINFO(context << "Failed to lock m_sync_lock, going back to download");
1336 goto skip;
1337 }
1338 MDEBUG(context << " lock m_sync_lock, adding blocks to chain...");
1339 MLOG_PEER_STATE("adding blocks");
1340
1341 {
1342 m_core.pause_mine();
1343 m_add_timer.resume();
1344 bool starting = true;
1346 m_add_timer.pause();
1347 m_core.resume_mine();
1348 if (!starting)
1350 });
1351 m_sync_start_time = boost::posix_time::microsec_clock::universal_time();
1352 m_sync_start_height = m_core.get_current_blockchain_height();
1354
1355 while (1)
1356 {
1357 const uint64_t previous_height = m_core.get_current_blockchain_height();
1358 uint64_t start_height;
1359 std::vector<cryptonote::block_complete_entry> blocks;
1360 boost::uuids::uuid span_connection_id;
1362 if (!m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin))
1363 {
1364 MDEBUG(context << " no next span found, going back to download");
1365 break;
1366 }
1367
1368 if (blocks.empty())
1369 {
1370 MERROR(context << "Next span has no blocks");
1371 m_block_queue.remove_spans(span_connection_id, start_height);
1372 continue;
1373 }
1374
1375 MDEBUG(context << " next span in the queue has blocks " << start_height << "-" << (start_height + blocks.size() - 1)
1376 << ", we need " << previous_height);
1377
1378 block new_block;
1379 crypto::hash last_block_hash;
1380 if (!parse_and_validate_block_from_blob(blocks.back().block, new_block, last_block_hash))
1381 {
1382 MERROR(context << "Failed to parse block, but it should already have been parsed");
1383 m_block_queue.remove_spans(span_connection_id, start_height);
1384 continue;
1385 }
1386 if (m_core.have_block(last_block_hash))
1387 {
1388 const uint64_t subchain_height = start_height + blocks.size();
1389 LOG_DEBUG_CC(context, "These are old blocks, ignoring: blocks " << start_height << " - " << (subchain_height-1) << ", blockchain height " << m_core.get_current_blockchain_height());
1390 m_block_queue.remove_spans(span_connection_id, start_height);
1392 continue;
1393 }
1394 if (!parse_and_validate_block_from_blob(blocks.front().block, new_block))
1395 {
1396 MERROR(context << "Failed to parse block, but it should already have been parsed");
1397 m_block_queue.remove_spans(span_connection_id, start_height);
1398 continue;
1399 }
1400 bool parent_known = m_core.have_block(new_block.prev_id);
1401 if (!parent_known)
1402 {
1403 const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id);
1404 if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height)
1405 {
1406 MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id);
1407 drop_connection(span_connection_id);
1408 return 1;
1409 }
1410
1411 // it could be:
1412 // - later in the current chain
1413 // - later in an alt chain
1414 // - orphan
1415 // if it was requested, then it'll be resolved later, otherwise it's an orphan
1416 bool parent_requested = m_block_queue.requested(new_block.prev_id);
1417 if (!parent_requested)
1418 {
1419 // we might be able to ask for that block directly, as we now can request out of order,
1420 // otherwise we continue out of order, unless this block is the one we need, in which
1421 // case we request block hashes, though it might be safer to disconnect ?
1422 if (start_height > previous_height)
1423 {
1425 {
1426 MDEBUG(context << "Got block with unknown parent which was not requested, but peer does not have that block - dropping connection");
1427 if (!context.m_is_income)
1428 m_p2p->add_used_stripe_peer(context);
1429 drop_connection(context, false, true);
1430 return 1;
1431 }
1432 MDEBUG(context << "Got block with unknown parent which was not requested, but peer does not have that block - back to download");
1433
1434 goto skip;
1435 }
1436
1437 // this can happen if a connection was sicced onto a late span, if it did not have those blocks,
1438 // since we don't know that at the sic time
1439 LOG_ERROR_CCONTEXT("Got block with unknown parent which was not requested - querying block hashes");
1440 m_block_queue.remove_spans(span_connection_id, start_height);
1441 context.m_needed_objects.clear();
1442 context.m_last_response_height = 0;
1443 goto skip;
1444 }
1445
1446 // parent was requested, so we wait for it to be retrieved
1447 MINFO(context << " parent was requested, we'll get back to it");
1448 break;
1449 }
1450
1451 const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
1452
1453 if (starting)
1454 {
1455 starting = false;
1457 {
1458 const uint64_t tnow = tools::get_tick_count();
1460 MINFO("Restarting adding block after idle for " << ns/1e9 << " seconds");
1461 }
1462 }
1463
1464 std::vector<block> pblocks;
1465 if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
1466 {
1467 LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
1468 drop_connections(span_origin);
1469 return 1;
1470 }
1471 if (!pblocks.empty() && pblocks.size() != blocks.size())
1472 {
1473 m_core.cleanup_handle_incoming_blocks();
1474 LOG_ERROR_CCONTEXT("Internal error: blocks.size() != block_entry.txs.size()");
1475 return 1;
1476 }
1477
1478 bool stopped = false;
1479 auto cleanup_on_exit = epee::misc_utils::create_scope_leave_handler([this, &stopped, &context, span_connection_id, start_height]() {
1480 if (!m_core.cleanup_handle_incoming_blocks())
1481 {
1482 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1483 return;
1484 }
1485
1486 if (stopped)
1487 return;
1488
1489 m_block_queue.remove_spans(span_connection_id, start_height);
1490 });
1491
1492 uint64_t block_process_time_full = 0, transactions_process_time_full = 0;
1493 size_t num_txs = 0, blockidx = 0;
1494 for(const block_complete_entry& block_entry: blocks)
1495 {
1496 if (m_stopping)
1497 {
1498 stopped = true;
1499 return 1;
1500 }
1501
1502 // process transactions
1503 TIME_MEASURE_START(transactions_process_time);
1504 num_txs += block_entry.txs.size();
1505
1506 pool_supplement block_txs;
1507 if (!make_full_pool_supplement_from_block_entry(block_entry, block_txs))
1508 {
1509 drop_connections(span_origin);
1510 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1511 LOG_ERROR_CCONTEXT("transaction parsing failed for 1 or more txs in NOTIFY_RESPONSE_GET_OBJECTS,"
1512 "dropping connections");
1513 drop_connection(context, false, true);
1514 return 1;
1515 }))
1516 LOG_ERROR_CCONTEXT("span connection id not found");
1517
1518 return 1;
1519 }
1520 TIME_MEASURE_FINISH(transactions_process_time);
1521 transactions_process_time_full += transactions_process_time;
1522
1523 // process block
1524
1525 TIME_MEASURE_START(block_process_time);
1527
1528 m_core.handle_incoming_block(block_entry.block,
1529 pblocks.empty() ? NULL : &pblocks[blockidx],
1530 bvc,
1531 block_txs,
1532 false); // <--- process block
1533
1534 if(bvc.m_verifivation_failed)
1535 {
1536 drop_connections(span_origin);
1537 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1538 LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
1539 drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
1540 return 1;
1541 }))
1542 LOG_ERROR_CCONTEXT("span connection id not found");
1543
1544 return 1;
1545 }
1546 if(bvc.m_marked_as_orphaned)
1547 {
1548 drop_connections(span_origin);
1549 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1550 LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
1551 drop_connection(context, true, true);
1552 return 1;
1553 }))
1554 LOG_ERROR_CCONTEXT("span connection id not found");
1555
1556 return 1;
1557 }
1558
1559 TIME_MEASURE_FINISH(block_process_time);
1560 block_process_time_full += block_process_time;
1561 ++blockidx;
1562
1563 } // each download block
1564
1565 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");
1566
1567 cleanup_on_exit.reset();
1568
1569 const uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
1570 if (current_blockchain_height > previous_height)
1571 {
1572 const uint64_t target_blockchain_height = m_core.get_target_blockchain_height();
1573 const boost::posix_time::time_duration dt = boost::posix_time::microsec_clock::universal_time() - start;
1574 std::string progress_message = "";
1575 if (current_blockchain_height < target_blockchain_height)
1576 {
1577 uint64_t completion_percent = (current_blockchain_height * 100 / target_blockchain_height);
1578 if (completion_percent == 100) // never show 100% if not actually up to date
1579 completion_percent = 99;
1580 progress_message = " (" + std::to_string(completion_percent) + "%, "
1581 + std::to_string(target_blockchain_height - current_blockchain_height) + " left";
1582 std::string time_message = get_periodic_sync_estimate(current_blockchain_height, target_blockchain_height);
1583 if (!time_message.empty())
1584 {
1585 uint64_t total_blocks_to_sync = target_blockchain_height - m_sync_start_height;
1586 uint64_t total_blocks_synced = current_blockchain_height - m_sync_start_height;
1587 progress_message += ", " + std::to_string(total_blocks_synced * 100 / total_blocks_to_sync) + "% of total synced";
1588 progress_message += ", estimated " + time_message + " left";
1589 }
1590 progress_message += ")";
1591 }
1592 const uint32_t previous_stripe = tools::get_pruning_stripe(previous_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1593 const uint32_t current_stripe = tools::get_pruning_stripe(current_blockchain_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1594 std::string timing_message = "";
1595 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
1596 timing_message = std::string(" (") + std::to_string(dt.total_microseconds()/1e6) + " sec, "
1597 + std::to_string((current_blockchain_height - previous_height) * 1e6 / dt.total_microseconds())
1598 + " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued in "
1599 + std::to_string(m_block_queue.get_num_filled_spans()) + " spans, stripe "
1600 + std::to_string(previous_stripe) + " -> " + std::to_string(current_stripe);
1601 if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info"))
1602 timing_message += std::string(": ") + m_block_queue.get_overview(current_blockchain_height);
1603 MGINFO_YELLOW("Synced " << current_blockchain_height << "/" << target_blockchain_height
1604 << progress_message << timing_message);
1605 if (previous_stripe != current_stripe)
1606 notify_new_stripe(context, current_stripe);
1607 }
1608 }
1609 }
1610
1611 MLOG_PEER_STATE("stopping adding blocks");
1612
1613 if (should_download_next_span(context, false))
1614 {
1615 force_next_span = true;
1616 }
1617 else if (should_drop_connection(context, get_next_needed_pruning_stripe().first))
1618 {
1619 if (!context.m_is_income)
1620 {
1621 m_p2p->add_used_stripe_peer(context);
1622 drop_connection(context, false, false);
1623 }
1624 return 1;
1625 }
1626 }
1627
1628skip:
1629 if (!request_missing_objects(context, true, force_next_span))
1630 {
1631 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
1632 drop_connection(context, false, false);
1633 return 1;
1634 }
1635 return 1;
1636 }
1637 //------------------------------------------------------------------------------------------------------------------------
1638 template<class t_core>
1640 {
1641 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1642 {
1643 if (cntxt.m_connection_id == context.m_connection_id)
1644 return true;
1645 if (context.m_state == cryptonote_connection_context::state_normal)
1646 {
1647 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1648 if (stripe && peer_stripe && peer_stripe != stripe)
1649 return true;
1650 context.m_new_stripe_notification = true;
1651 LOG_PRINT_CCONTEXT_L2("requesting callback");
1652 ++context.m_callback_request_count;
1653 m_p2p->request_callback(context);
1654 MLOG_PEER_STATE("requesting callback");
1655 }
1656 return true;
1657 });
1658 }
1659 //------------------------------------------------------------------------------------------------------------------------
1660 template<class t_core>
1668 //------------------------------------------------------------------------------------------------------------------------
1669 template<class t_core>
1671 {
1672 MTRACE("Checking for idle peers...");
1673 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1674 {
1675 if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
1676 {
1677 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1678 const boost::posix_time::time_duration dt = now - context.m_last_request_time;
1679 const auto ms = dt.total_microseconds();
1680 if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
1681 {
1682 context.m_idle_peer_notification = true;
1683 LOG_PRINT_CCONTEXT_L2("requesting callback");
1684 ++context.m_callback_request_count;
1685 m_p2p->request_callback(context);
1686 MLOG_PEER_STATE("requesting callback");
1687 }
1688 }
1689 return true;
1690 });
1691
1692 return true;
1693 }
1694 //------------------------------------------------------------------------------------------------------------------------
1695 template<class t_core>
1697 {
1698 const uint64_t target = m_core.get_target_blockchain_height();
1699 const uint64_t height = m_core.get_current_blockchain_height();
1700 if (target > height) // if we're not synced yet, don't do it
1701 return true;
1702
1703 MTRACE("Checking for outgoing syncing peers...");
1704 std::unordered_map<epee::net_utils::zone, unsigned> n_syncing, n_synced;
1705 std::unordered_map<epee::net_utils::zone, boost::uuids::uuid> last_synced_peer_id;
1706 std::vector<epee::net_utils::zone> zones;
1707 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1708 {
1709 if (!peer_id || context.m_is_income) // only consider connected outgoing peers
1710 return true;
1711
1712 const epee::net_utils::zone zone = context.m_remote_address.get_zone();
1713 if (n_syncing.find(zone) == n_syncing.end())
1714 {
1715 n_syncing[zone] = 0;
1716 n_synced[zone] = 0;
1717 last_synced_peer_id[zone] = boost::uuids::nil_uuid();
1718 zones.push_back(zone);
1719 }
1720
1722 ++n_syncing[zone];
1723 if (context.m_state == cryptonote_connection_context::state_normal)
1724 {
1725 ++n_synced[zone];
1726 if (!context.m_anchor)
1727 last_synced_peer_id[zone] = context.m_connection_id;
1728 }
1729 return true;
1730 });
1731
1732 for (const auto& zone : zones)
1733 {
1734 const unsigned int max_out_peers = get_max_out_peers(zone);
1735 MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1736
1737 // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor
1738 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())
1739 {
1740 if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1741 MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1742 drop_connection(ctx, false, false);
1743 return true;
1744 }))
1745 MDEBUG("Failed to find peer we wanted to drop");
1746 }
1747 }
1748
1749 return true;
1750 }
1751 //------------------------------------------------------------------------------------------------------------------------
1752 template<class t_core>
1754 {
1755 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1756 {
1757 if (context.m_state == cryptonote_connection_context::state_standby)
1758 {
1759 LOG_PRINT_CCONTEXT_L2("requesting callback");
1760 ++context.m_callback_request_count;
1761 m_p2p->request_callback(context);
1762 }
1763 return true;
1764 });
1765 return true;
1766 }
1767 //------------------------------------------------------------------------------------------------------------------------
1768 template<class t_core>
1770 {
1771 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
1773 {
1774 LOG_ERROR_CCONTEXT("Requested chain before handshake, dropping connection");
1775 drop_connection(context, false, false);
1776 return 1;
1777 }
1779 if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
1780 {
1781 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
1782 return 1;
1783 }
1784 if (r.m_block_ids.size() >= 2)
1785 {
1787 if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
1788 {
1789 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
1790 return 1;
1791 }
1792 r.first_block = cryptonote::block_to_blob(b);
1793 }
1794 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());
1796 return 1;
1797 }
1798 //------------------------------------------------------------------------------------------------------------------------
1799 template<class t_core>
1801 {
1802 std::vector<crypto::hash> hashes;
1803 boost::posix_time::ptime request_time;
1804 boost::uuids::uuid connection_id;
1805 bool filled;
1806
1807 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
1808 if (context.m_remote_blockchain_height <= blockchain_height)
1809 return false;
1810 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1811 const bool has_next_block = tools::has_unpruned_block(blockchain_height, context.m_remote_blockchain_height, context.m_pruning_seed);
1812 if (has_next_block)
1813 {
1814 if (!m_block_queue.has_next_span(blockchain_height, filled, request_time, connection_id))
1815 {
1816 MDEBUG(context << " we should download it as no peer reserved it");
1817 return true;
1818 }
1819 if (!filled)
1820 {
1821 const long dt = (now - request_time).total_microseconds();
1823 {
1824 MDEBUG(context << " we should download it as it's not been received yet after " << dt/1e6);
1825 return true;
1826 }
1827
1828 // in standby, be ready to double download early since we're idling anyway
1829 // let the fastest peer trigger first
1830 const double dl_speed = context.m_max_speed_down;
1831 if (standby && dt >= REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY && dl_speed > 0)
1832 {
1833 bool download = false;
1834 if (m_p2p->for_connection(connection_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1835 const time_t nowt = time(NULL);
1836 const time_t time_since_last_recv = nowt - ctx.m_last_recv;
1837 const float last_activity = std::min((float)time_since_last_recv, dt/1e6f);
1838 const bool stalled = last_activity > LAST_ACTIVITY_STALL_THRESHOLD;
1839 if (stalled)
1840 {
1841 MDEBUG(context << " we should download it as the downloading peer is stalling for " << nowt - ctx.m_last_recv << " seconds");
1842 download = true;
1843 return true;
1844 }
1845
1846 // estimate the standby peer can give us 80% of its max speed
1847 // and let it download if that speed is > N times as fast as the current one
1848 // N starts at 10 after REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY,
1849 // decreases to 1.25 at REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD,
1850 // so that at times goes without the download being done, a retry becomes easier
1851 const float max_multiplier = 10.f;
1852 const float min_multiplier = 1.25f;
1853 float multiplier = max_multiplier;
1855 {
1856 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);
1857 multiplier = std::min(max_multiplier, std::max(min_multiplier, multiplier));
1858 }
1859 if (dl_speed * .8f > ctx.m_current_speed_down * multiplier)
1860 {
1861 MDEBUG(context << " we should download it as we are substantially faster (" << dl_speed << " vs "
1862 << ctx.m_current_speed_down << ", multiplier " << multiplier << " after " << dt/1e6 << " seconds)");
1863 download = true;
1864 return true;
1865 }
1866 return true;
1867 }))
1868 {
1869 if (download)
1870 return true;
1871 }
1872 else
1873 {
1874 MWARNING(context << " we should download it as the downloading peer is unexpectedly not known to us");
1875 return true;
1876 }
1877 }
1878 }
1879 }
1880
1881 return false;
1882 }
1883 //------------------------------------------------------------------------------------------------------------------------
1884 template<class t_core>
1886 {
1887 if (context.m_anchor)
1888 {
1889 MDEBUG(context << "This is an anchor peer, not dropping");
1890 return false;
1891 }
1892 if (context.m_pruning_seed == 0)
1893 {
1894 MDEBUG(context << "This peer is not striped, not dropping");
1895 return false;
1896 }
1897
1898 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1899 if (next_stripe == peer_stripe)
1900 {
1901 MDEBUG(context << "This peer has needed stripe " << peer_stripe << ", not dropping");
1902 return false;
1903 }
1904 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1905 if (m_sync_pruned_blocks && local_stripe && next_stripe != local_stripe)
1906 {
1907 MDEBUG(context << "We can sync pruned blocks off this peer, not dropping");
1908 return false;
1909 }
1910
1911 if (!context.m_needed_objects.empty())
1912 {
1913 const uint64_t next_available_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
1914 if (tools::has_unpruned_block(next_available_block_height, context.m_remote_blockchain_height, context.m_pruning_seed))
1915 {
1916 MDEBUG(context << "This peer has unpruned next block at height " << next_available_block_height << ", not dropping");
1917 return false;
1918 }
1919 }
1920
1921 if (next_stripe > 0)
1922 {
1923 unsigned int n_out_peers = 0, n_peers_on_next_stripe = 0;
1924 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
1925 if (!ctx.m_is_income)
1926 ++n_out_peers;
1928 ++n_peers_on_next_stripe;
1929 return true;
1930 });
1931 // TODO: investigate tallying by zone and comparing to max out peers by zone
1932 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
1933 const uint32_t distance = (peer_stripe + (1<<CRYPTONOTE_PRUNING_LOG_STRIPES) - next_stripe) % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
1934 if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2)
1935 {
1936 MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers ("
1937 << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe <<
1938 " is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space");
1939 return true;
1940 }
1941 }
1942 MDEBUG(context << "End of checks, not dropping");
1943 return false;
1944 }
1945 //------------------------------------------------------------------------------------------------------------------------
1946 template<class t_core>
1948 {
1949 // take out blocks we already have
1950 size_t skip = 0;
1951 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))))
1952 {
1953 // if we're popping the last hash, record it so we can ask again from that hash,
1954 // this prevents never being able to progress on peers we get old hash lists from
1955 if (skip + 1 == context.m_needed_objects.size())
1956 context.m_last_known_hash = context.m_needed_objects[skip].first;
1957 ++skip;
1958 }
1959 if (skip > 0)
1960 {
1961 MDEBUG(context << "skipping " << skip << "/" << context.m_needed_objects.size() << " blocks");
1962 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
1963 }
1964 return skip;
1965 }
1966 //------------------------------------------------------------------------------------------------------------------------
1967 template<class t_core>
1968 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
1969 {
1971 return false;
1972 if (!m_core.is_within_compiled_block_hash_area(first_block_height + nblocks - 1))
1973 return false;
1974 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1975 if (local_stripe == 0)
1976 return false;
1977 // don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
1978 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP + 1);
1979 if (first_block_height < bp_fork_height)
1980 return false;
1981 // assumes the span size is less or equal to the stripe size
1982 bool full_data_needed = tools::get_pruning_stripe(first_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe
1983 || tools::get_pruning_stripe(first_block_height + nblocks - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe;
1984 if (full_data_needed)
1985 return false;
1986 if (check_block_weights && !m_core.has_block_weights(first_block_height, nblocks))
1987 return false;
1988 return true;
1989 }
1990 //------------------------------------------------------------------------------------------------------------------------
1991 template<class t_core>
1992 bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks, bool force_next_span)
1993 {
1994 // flush stale spans
1995 std::set<boost::uuids::uuid> live_connections;
1996 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
1997 live_connections.insert(context.m_connection_id);
1998 return true;
1999 });
2000 m_block_queue.flush_stale_spans(live_connections);
2001
2002 // if we don't need to get next span, and the block queue is full enough, wait a bit
2003 if (!force_next_span)
2004 {
2005 do
2006 {
2007 size_t nspans = m_block_queue.get_num_filled_spans();
2008 size_t size = m_block_queue.get_data_size();
2009 const uint64_t bc_height = m_core.get_current_blockchain_height();
2010 const auto next_needed_pruning_stripe = get_next_needed_pruning_stripe();
2011 const uint32_t add_stripe = tools::get_pruning_stripe(bc_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2012 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2013 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
2014 const size_t block_queue_size_threshold = m_block_download_max_size ? m_block_download_max_size : BLOCK_QUEUE_SIZE_THRESHOLD;
2015 bool queue_proceed = nspans < BLOCK_QUEUE_NSPANS_THRESHOLD || size < block_queue_size_threshold;
2016 // get rid of blocks we already requested, or already have
2017 if (skip_unneeded_hashes(context, true) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2018 {
2019 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(bc_height))
2020 {
2021 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2022 return false;
2023 }
2024 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2025 context.set_state_normal();
2026 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2028 return true;
2029 }
2030 uint64_t next_needed_height = m_block_queue.get_next_needed_height(bc_height);
2031 uint64_t next_block_height;
2032 if (context.m_needed_objects.empty())
2033 next_block_height = next_needed_height;
2034 else
2035 next_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2036 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);
2037 bool stripe_proceed_secondary = tools::has_unpruned_block(next_block_height, context.m_remote_blockchain_height, context.m_pruning_seed);
2038 bool proceed = stripe_proceed_main || (queue_proceed && stripe_proceed_secondary);
2039 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)))
2040 {
2041 if (!context.m_is_income)
2042 m_p2p->add_used_stripe_peer(context);
2043 return false; // drop outgoing connections
2044 }
2045
2046 MDEBUG(context << "proceed " << proceed << " (queue " << queue_proceed << ", stripe " << stripe_proceed_main << "/" <<
2047 stripe_proceed_secondary << "), " << next_needed_pruning_stripe.first << "-" << next_needed_pruning_stripe.second <<
2048 " needed, bc add stripe " << add_stripe << ", we have " << peer_stripe << "), bc_height " << bc_height);
2049 MDEBUG(context << " - next_block_height " << next_block_height << ", seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2050 ", next_needed_height "<< next_needed_height);
2051 MDEBUG(context << " - last_response_height " << context.m_last_response_height << ", m_needed_objects size " << context.m_needed_objects.size());
2052
2053 // if we're waiting for next span, try to get it before unblocking threads below,
2054 // or a runaway downloading of future spans might happen
2055 if (stripe_proceed_main && should_download_next_span(context, true))
2056 {
2057 MDEBUG(context << " we should try for that next span too, we think we could get it faster, resuming");
2058 force_next_span = true;
2059 MLOG_PEER_STATE("resuming");
2060 break;
2061 }
2062
2063 if (proceed)
2064 {
2065 if (context.m_state != cryptonote_connection_context::state_standby)
2066 {
2067 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", resuming");
2068 MLOG_PEER_STATE("resuming");
2069 }
2070 break;
2071 }
2072
2073 // this one triggers if all threads are in standby, which should not happen,
2074 // but happened at least once, so we unblock at least one thread if so
2075 boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2076 if (sync.owns_lock())
2077 {
2078 bool filled = false;
2079 boost::posix_time::ptime time;
2080 boost::uuids::uuid connection_id;
2081 if (m_block_queue.has_next_span(m_core.get_current_blockchain_height(), filled, time, connection_id) && filled)
2082 {
2083 LOG_DEBUG_CC(context, "No other thread is adding blocks, and next span needed is ready, resuming");
2084 MLOG_PEER_STATE("resuming");
2086 ++context.m_callback_request_count;
2087 m_p2p->request_callback(context);
2088 return true;
2089 }
2090 else
2091 {
2092 sync.unlock();
2093
2094 // if this has gone on for too long, drop incoming connection to guard against some wedge state
2095 if (!context.m_is_income)
2096 {
2097 const uint64_t now = tools::get_tick_count();
2098 const uint64_t dt = now - m_last_add_end_time;
2100 {
2101 MDEBUG(context << "ns " << tools::ticks_to_ns(dt) << " from " << m_last_add_end_time << " and " << now);
2102 MDEBUG(context << "Block addition seems to have wedged, dropping connection");
2103 return false;
2104 }
2105 }
2106 }
2107 }
2108
2109 if (context.m_state != cryptonote_connection_context::state_standby)
2110 {
2111 if (!queue_proceed)
2112 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", pausing");
2113 else if (!stripe_proceed_main && !stripe_proceed_secondary)
2114 LOG_DEBUG_CC(context, "We do not have the stripe required to download another block, pausing");
2116 MLOG_PEER_STATE("pausing");
2117 }
2118
2119 return true;
2120 } while(0);
2122 }
2123
2124 MDEBUG(context << " request_missing_objects: check " << check_having_blocks << ", force_next_span " << force_next_span
2125 << ", m_needed_objects " << context.m_needed_objects.size() << " lrh " << context.m_last_response_height << ", chain "
2126 << m_core.get_current_blockchain_height() << ", pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed));
2127 if(context.m_needed_objects.size() || force_next_span)
2128 {
2129 //we know objects that we need, request this objects
2131 bool is_next = false;
2132 size_t count = 0;
2133 const size_t count_limit = m_core.get_block_sync_size(m_core.get_current_blockchain_height());
2134 std::pair<uint64_t, uint64_t> span = std::make_pair(0, 0);
2135 if (force_next_span)
2136 {
2137 if (span.second == 0)
2138 {
2139 std::vector<crypto::hash> hashes;
2140 boost::uuids::uuid span_connection_id;
2141 boost::posix_time::ptime time;
2142 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2143 if (span.second > 0)
2144 {
2145 is_next = true;
2146 req.blocks.reserve(hashes.size());
2147 for (const auto &hash: hashes)
2148 {
2149 req.blocks.push_back(hash);
2150 context.m_requested_objects.insert(hash);
2151 }
2152 m_block_queue.reset_next_span_time();
2153 }
2154 }
2155 }
2156 if (span.second == 0)
2157 {
2158 MDEBUG(context << " span size is 0");
2159 if (context.m_last_response_height + 1 < context.m_needed_objects.size())
2160 {
2161 MERROR(context << " ERROR: inconsistent context: lrh " << context.m_last_response_height << ", nos " << context.m_needed_objects.size());
2162 context.m_needed_objects.clear();
2163 context.m_last_response_height = 0;
2164 goto skip;
2165 }
2166 if (skip_unneeded_hashes(context, false) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2167 {
2168 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(m_core.get_current_blockchain_height()))
2169 {
2170 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2171 return false;
2172 }
2173 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2174 context.set_state_normal();
2175 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2177 return true;
2178 }
2179
2180 const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2181 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
2182 bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
2183 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);
2184 MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
2185 if (span.second > 0)
2186 {
2187 const uint32_t stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2188 if (context.m_pruning_seed && stripe != tools::get_pruning_stripe(context.m_pruning_seed))
2189 {
2190 MDEBUG(context << " starting early on next seed (" << span.first << " with stripe " << stripe <<
2191 ", context seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ")");
2192 }
2193 }
2194 }
2195 if (span.second == 0 && !force_next_span)
2196 {
2197 MDEBUG(context << " still no span reserved, we may be in the corner case of next span scheduled and everything else scheduled/filled");
2198 std::vector<crypto::hash> hashes;
2199 boost::uuids::uuid span_connection_id;
2200 boost::posix_time::ptime time;
2201 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2202 if (span.second > 0 && !tools::has_unpruned_block(span.first, context.m_remote_blockchain_height, context.m_pruning_seed))
2203 span = std::make_pair(0, 0);
2204 if (span.second > 0)
2205 {
2206 is_next = true;
2207 req.blocks.reserve(hashes.size());
2208 for (const auto &hash: hashes)
2209 {
2210 req.blocks.push_back(hash);
2211 ++count;
2212 context.m_requested_objects.insert(hash);
2213 // that's atrocious O(n) wise, but this is rare
2214 auto i = std::find_if(context.m_needed_objects.begin(), context.m_needed_objects.end(),
2215 [&hash](const std::pair<crypto::hash, uint64_t> &o) { return o.first == hash; });
2216 if (i != context.m_needed_objects.end())
2217 context.m_needed_objects.erase(i);
2218 }
2219 }
2220 }
2221 MDEBUG(context << " span: " << span.first << "/" << span.second << " (" << span.first << " - " << (span.first + span.second - 1) << ")");
2222 if (span.second > 0)
2223 {
2224 if (!is_next)
2225 {
2226 const uint64_t first_context_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2227 uint64_t skip = span.first - first_context_block_height;
2228 if (skip > context.m_needed_objects.size())
2229 {
2230 MERROR("ERROR: skip " << skip << ", m_needed_objects " << context.m_needed_objects.size() << ", first_context_block_height" << first_context_block_height);
2231 return false;
2232 }
2233 if (skip > 0)
2234 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
2235 if (context.m_needed_objects.size() < span.second)
2236 {
2237 MERROR("ERROR: span " << span.first << "/" << span.second << ", m_needed_objects " << context.m_needed_objects.size());
2238 return false;
2239 }
2240
2241 req.blocks.reserve(req.blocks.size() + span.second);
2242 for (size_t n = 0; n < span.second; ++n)
2243 {
2244 req.blocks.push_back(context.m_needed_objects[n].first);
2245 ++count;
2246 context.m_requested_objects.insert(context.m_needed_objects[n].first);
2247 }
2248 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + span.second, context.m_needed_objects.end());
2249 }
2250
2251 req.prune = should_ask_for_pruned_data(context, span.first, span.second, true);
2252
2253 // if we need to ask for full data and that peer does not have the right stripe, we can't ask it
2254 if (!req.prune && context.m_pruning_seed)
2255 {
2256 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2257 const uint32_t first_stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2258 const uint32_t last_stripe = tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2259 if (((first_stripe && peer_stripe != first_stripe) || (last_stripe && peer_stripe != last_stripe)) && !m_sync_pruned_blocks)
2260 {
2261 MDEBUG(context << "We need full data, but the peer does not have it, dropping peer");
2262 return false;
2263 }
2264 }
2265 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2266 context.m_expect_height = span.first;
2267 context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
2268 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
2269 << "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
2270 //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());
2271
2272 MDEBUG("Asking for " << (req.prune ? "pruned" : "full") << " data, start/end "
2273 << tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2274 << "/" << tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2275 << ", ours " << tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed()) << ", peer stripe " << tools::get_pruning_stripe(context.m_pruning_seed));
2276
2277 context.m_num_requested += req.blocks.size();
2279 MLOG_PEER_STATE("requesting objects");
2280 return true;
2281 }
2282
2283 // we can do nothing, so drop this peer to make room for others unless we think we've downloaded all we need
2284 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
2285 if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
2286 {
2287 context.set_state_normal();
2288 MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
2289 return true;
2290 }
2291 MLOG_PEER_STATE("We can download nothing from this peer, dropping");
2292 return false;
2293 }
2294
2295skip:
2296 context.m_needed_objects.clear();
2297
2298 // we might have been called from the "received chain entry" handler, and end up
2299 // here because we can't use any of those blocks (maybe because all of them are
2300 // actually already requested). In this case, if we can add blocks instead, do so
2301 if (m_core.get_current_blockchain_height() < m_core.get_target_blockchain_height())
2302 {
2303 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2304 if (sync.owns_lock())
2305 {
2306 uint64_t start_height;
2307 std::vector<cryptonote::block_complete_entry> blocks;
2308 boost::uuids::uuid span_connection_id;
2310 if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
2311 {
2312 LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
2313 MLOG_PEER_STATE("will try to add blocks next");
2315 ++context.m_callback_request_count;
2316 m_p2p->request_callback(context);
2317 return true;
2318 }
2319 }
2320 }
2321
2322 if(context.m_last_response_height < context.m_remote_blockchain_height-1)
2323 {//we have to fetch more objects ids, request blockchain entry
2324
2326 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
2327 CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
2328
2329 // we'll want to start off from where we are on that peer, which may not be added yet
2330 if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
2331 {
2332 context.m_expect_height = std::numeric_limits<uint64_t>::max();
2333 r.block_ids.push_front(context.m_last_known_hash);
2334 }
2335
2336 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
2337 r.prune = m_sync_pruned_blocks;
2338
2339 //std::string blob; // for calculate size of request
2340 //epee::serialization::store_t_to_binary(r, blob);
2341 //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());
2342 //LOG_PRINT_CCONTEXT_L1("r = " << 200);
2343
2344 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2345 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
2346 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
2348 MLOG_PEER_STATE("requesting chain");
2349 }else
2350 {
2351 CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1
2352 && !context.m_needed_objects.size()
2353 && !context.m_requested_objects.size(), false, "request_missing_blocks final condition failed!"
2354 << "\r\nm_last_response_height=" << context.m_last_response_height
2355 << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height
2356 << "\r\nm_needed_objects.size()=" << context.m_needed_objects.size()
2357 << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
2358 << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
2359
2360 context.set_state_normal();
2361 if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
2362 {
2363 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2365 }
2366 else
2367 {
2368 MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
2369 }
2370 }
2371 return true;
2372 }
2373 //------------------------------------------------------------------------------------------------------------------------
2374 template<class t_core>
2376 {
2377 bool val_expected = false;
2378 uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
2379 if(!m_core.is_within_compiled_block_hash_area(current_blockchain_height) && m_synchronized.compare_exchange_strong(val_expected, true))
2380 {
2381 if ((current_blockchain_height > m_sync_start_height) && (m_sync_spans_downloaded > 0))
2382 {
2383 uint64_t synced_blocks = current_blockchain_height - m_sync_start_height;
2384 // Report only after syncing an "interesting" number of blocks:
2385 if (synced_blocks > 20)
2386 {
2387 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2388 uint64_t synced_seconds = (now - m_sync_start_time).total_seconds();
2389 if (synced_seconds == 0)
2390 {
2391 synced_seconds = 1;
2392 }
2393 float blocks_per_second = (1000 * synced_blocks / synced_seconds) / 1000.0f;
2394 MGINFO_YELLOW("Synced " << synced_blocks << " blocks in "
2395 << tools::get_human_readable_timespan(synced_seconds) << " (" << blocks_per_second << " blocks per second)");
2396 }
2397 }
2398 MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
2399 << "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
2400 << ENDL
2401 << "Use the \"help\" command to see the list of available commands." << ENDL
2402 << "**********************************************************************");
2403 m_sync_timer.pause();
2404 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
2405 {
2406 const uint64_t sync_time = m_sync_timer.value();
2407 const uint64_t add_time = m_add_timer.value();
2408 if (sync_time && add_time)
2409 {
2410 MCLOG_YELLOW(el::Level::Info, "sync-info", "Sync time: " << sync_time/1e9/60 << " min, idle time " <<
2411 (100.f * (1.0f - add_time / (float)sync_time)) << "%" << ", " <<
2412 (10 * m_sync_download_objects_size / 1024 / 1024) / 10.f << " + " <<
2413 (10 * m_sync_download_chain_size / 1024 / 1024) / 10.f << " MB downloaded, " <<
2414 100.0f * m_sync_old_spans_downloaded / m_sync_spans_downloaded << "% old spans, " <<
2415 100.0f * m_sync_bad_spans_downloaded / m_sync_spans_downloaded << "% bad spans");
2416 }
2417 }
2418 m_core.on_synchronized();
2419 }
2420 m_core.safesyncmode(true);
2421 m_p2p->clear_used_stripe_peers();
2422
2423 // ask for txpool complement from any suitable node if we did not yet
2424 val_expected = true;
2425 if (m_ask_for_txpool_complement.compare_exchange_strong(val_expected, false))
2426 {
2427 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
2428 {
2430 {
2431 MDEBUG(context << "not ready, ignoring");
2432 return true;
2433 }
2434 if (!request_txpool_complement(context))
2435 {
2436 MERROR(context << "Failed to request txpool complement");
2437 return true;
2438 }
2439 return false;
2440 });
2441 }
2442
2443 return true;
2444 }
2445 //------------------------------------------------------------------------------------------------------------------------
2446 template<class t_core>
2448 {
2449 size_t count = 0;
2450 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2452 ++count;
2453 return true;
2454 });
2455 return count;
2456 }
2457 //------------------------------------------------------------------------------------------------------------------------
2458 template<class t_core>
2460 {
2461 MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
2462 << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height << ", expect height=" << context.m_expect_height);
2463 MLOG_PEER_STATE("received chain");
2464
2465 if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
2466 {
2467 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
2468 drop_connection(context, true, false);
2469 return 1;
2470 }
2471 context.m_expect_response = 0;
2472 if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
2473 {
2474 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
2475 drop_connection(context, true, false);
2476 return 1;
2477 }
2478
2479 context.m_last_request_time = boost::date_time::not_a_date_time;
2480
2481 m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
2482
2483 if(!arg.m_block_ids.size())
2484 {
2485 LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
2486 drop_connection(context, true, false);
2487 return 1;
2488 }
2489 if (arg.total_height < arg.m_block_ids.size() || arg.start_height > arg.total_height - arg.m_block_ids.size())
2490 {
2491 LOG_ERROR_CCONTEXT("sent invalid start/nblocks/height, dropping connection");
2492 drop_connection(context, true, false);
2493 return 1;
2494 }
2495 if (!arg.m_block_weights.empty() && arg.m_block_weights.size() != arg.m_block_ids.size())
2496 {
2497 LOG_ERROR_CCONTEXT("sent invalid block weight array, dropping connection");
2498 drop_connection(context, true, false);
2499 return 1;
2500 }
2501 MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back());
2502
2503 if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() > BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT)
2504 {
2505 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size());
2506 drop_connection(context, false, false);
2507 return 1;
2508 }
2509 if (arg.total_height < context.m_remote_blockchain_height)
2510 {
2511 MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
2512 hit_score(context, 1);
2513 }
2514 context.m_remote_blockchain_height = arg.total_height;
2515 context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
2516 if(context.m_last_response_height > context.m_remote_blockchain_height)
2517 {
2518 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
2519 << ", m_start_height=" << arg.start_height
2520 << ", m_block_ids.size()=" << arg.m_block_ids.size());
2521 drop_connection(context, false, false);
2522 return 1;
2523 }
2524
2525 uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
2526 if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
2527 {
2528 LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection");
2529 drop_connection(context, true, false);
2530 return 1;
2531 }
2532
2533 context.m_expected_heights_start = arg.start_height;
2534
2535 context.m_expected_heights.clear();
2536 context.m_expected_heights.reserve(arg.m_block_ids.size());
2537 context.m_needed_objects.clear();
2538 context.m_needed_objects.reserve(arg.m_block_ids.size());
2539 uint64_t added = 0;
2540 std::unordered_set<crypto::hash> blocks_found;
2541 bool expect_unknown = false;
2542 for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
2543 {
2544 if (!blocks_found.insert(arg.m_block_ids[i]).second)
2545 {
2546 LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
2547 drop_connection_with_score(context, 5, false);
2548 return 1;
2549 }
2550 int where;
2551 const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
2552 if (i == 0)
2553 {
2554 // our outgoing chainlist only has proven blocks (i.e. downloaded)
2555 if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
2556 {
2557 LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
2558 drop_connection_with_score(context, 5, false);
2559 return 1;
2560 }
2561 if (!have_block)
2562 expect_unknown = true;
2563 }
2564 if (0 < i)
2565 {
2566 // after the first, blocks may be known or unknown, but if they are known,
2567 // they should be at the same height if on the main chain
2568 if (have_block)
2569 {
2570 switch (where)
2571 {
2572 default:
2573 case HAVE_BLOCK_INVALID:
2574 LOG_ERROR_CCONTEXT("Block is invalid or known without known type, dropping connection");
2575 drop_connection(context, true, false);
2576 return 1;
2578 if (expect_unknown)
2579 {
2580 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2581 drop_connection_with_score(context, 5, false);
2582 return 1;
2583 }
2584 if (m_core.get_block_id_by_height(arg.start_height + i) != arg.m_block_ids[i])
2585 {
2586 LOG_ERROR_CCONTEXT("Block is on the main chain, but not at the expected height, dropping connection");
2587 drop_connection_with_score(context, 5, false);
2588 return 1;
2589 }
2590 break;
2592 if (expect_unknown)
2593 {
2594 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2595 drop_connection_with_score(context, 5, false);
2596 return 1;
2597 }
2598 break;
2599 }
2600 }
2601 else
2602 expect_unknown = true;
2603 }
2604 const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
2605 context.m_expected_heights.push_back(arg.m_block_ids[i]);
2606 context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
2607 if (++added == n_use_blocks)
2608 break;
2609 }
2610 context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
2611
2612 if (!request_missing_objects(context, false))
2613 {
2614 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
2615 drop_connection(context, false, false);
2616 return 1;
2617 }
2618
2619 if (arg.total_height > m_core.get_target_blockchain_height())
2620 m_core.set_target_blockchain_height(arg.total_height);
2621
2622 context.m_num_requested = 0;
2623 return 1;
2624 }
2625 //------------------------------------------------------------------------------------------------------------------------
2626 template<class t_core>
2628 {
2629 // sort peers between fluffy ones and others
2630 std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> fluffyConnections;
2631 m_p2p->for_each_connection([this, &exclude_context, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
2632 {
2633 // peer_id also filters out connections before handshake
2634 if (peer_id && exclude_context.m_connection_id != context.m_connection_id && context.m_remote_address.get_zone() == epee::net_utils::zone::public_)
2635 {
2636 LOG_DEBUG_CC(context, "RELAYING FLUFFY BLOCK TO PEER");
2637 fluffyConnections.push_back({context.m_remote_address.get_zone(), context.m_connection_id});
2638 }
2639 return true;
2640 });
2641
2642 // send fluffy ones first, we want to encourage people to run that
2643 if (!fluffyConnections.empty())
2644 {
2645 epee::levin::message_writer fluffyBlob{32 * 1024};
2647 m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, std::move(fluffyBlob), std::move(fluffyConnections));
2648 }
2649
2650 return true;
2651 }
2652 //------------------------------------------------------------------------------------------------------------------------
2653 template<class t_core>
2655 {
2656 /* Push all outgoing transactions to this function. The behavior needs to
2657 identify how the transaction is going to be relayed, and then update the
2658 local mempool before doing the relay. The code was already updating the
2659 DB twice on received transactions - it is difficult to workaround this
2660 due to the internal design. */
2661 return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid;
2662 }
2663 //------------------------------------------------------------------------------------------------------------------------
2664 template<class t_core>
2666 {
2668 if (!m_core.get_pool_transaction_hashes(r.hashes, false))
2669 {
2670 MERROR("Failed to get txpool hashes");
2671 return false;
2672 }
2673 MLOG_P2P_MESSAGE("-->>NOTIFY_GET_TXPOOL_COMPLEMENT: hashes.size()=" << r.hashes.size() );
2675 MLOG_PEER_STATE("requesting txpool complement");
2676 return true;
2677 }
2678 //------------------------------------------------------------------------------------------------------------------------
2679 template<class t_core>
2681 {
2682 if (score <= 0)
2683 {
2684 MERROR("Negative score hit");
2685 return;
2686 }
2687 context.m_score -= score;
2688 if (context.m_score <= DROP_PEERS_ON_SCORE)
2689 drop_connection_with_score(context, 5, false);
2690 }
2691 //------------------------------------------------------------------------------------------------------------------------
2692 template<class t_core>
2694 {
2695 std::stringstream ss;
2696 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2697 m_p2p->for_each_connection([&](const connection_context &ctx, nodetool::peerid_type peer_id, uint32_t support_flags) {
2699 char state_char = cryptonote::get_protocol_state_char(ctx.m_state);
2700 ss << stripe + state_char;
2701 if (ctx.m_last_request_time != boost::date_time::not_a_date_time)
2702 ss << (((now - ctx.m_last_request_time).total_microseconds() > IDLE_PEER_KICK_TIME) ? "!" : "?");
2703 ss << + " ";
2704 return true;
2705 });
2706 return ss.str();
2707 }
2708 //------------------------------------------------------------------------------------------------------------------------
2709 template<class t_core>
2711 {
2712 const uint64_t want_height_from_blockchain = m_core.get_current_blockchain_height();
2713 const uint64_t want_height_from_block_queue = m_block_queue.get_next_needed_height(want_height_from_blockchain);
2714 const uint64_t want_height = std::max(want_height_from_blockchain, want_height_from_block_queue);
2715 uint64_t blockchain_height = m_core.get_target_blockchain_height();
2716 // 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
2717 if (blockchain_height == 0)
2718 blockchain_height = CRYPTONOTE_MAX_BLOCK_NUMBER;
2719 const uint32_t next_pruning_stripe = tools::get_pruning_stripe(want_height, blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2720 if (next_pruning_stripe == 0)
2721 return std::make_pair(0, 0);
2722 // if we already have a few peers on this stripe, but none on next one, try next one
2723 unsigned int n_next = 0, n_subsequent = 0, n_others = 0;
2724 const uint32_t subsequent_pruning_stripe = 1 + next_pruning_stripe % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
2725 m_p2p->for_each_connection([&](const connection_context &context, nodetool::peerid_type peer_id, uint32_t support_flags) {
2727 {
2728 if (context.m_pruning_seed == 0 || tools::get_pruning_stripe(context.m_pruning_seed) == next_pruning_stripe)
2729 ++n_next;
2730 else if (tools::get_pruning_stripe(context.m_pruning_seed) == subsequent_pruning_stripe)
2731 ++n_subsequent;
2732 else
2733 ++n_others;
2734 }
2735 return true;
2736 });
2737 // TODO: investigate tallying by zone and comparing to max out peers by zone
2738 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
2739 const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0);
2740 const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe;
2741 MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" <<
2742 want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " <<
2743 next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " <<
2744 subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" <<
2745 (ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) <<
2746 "), current peers " << po);
2747 return std::make_pair(next_pruning_stripe, ret_stripe);
2748 }
2749 //------------------------------------------------------------------------------------------------------------------------
2750 template<class t_core>
2752 {
2753 const uint64_t target = m_core.get_target_blockchain_height();
2754 const uint64_t height = m_core.get_current_blockchain_height();
2755 if (target && target <= height)
2756 return false;
2757 size_t n_out_peers = 0;
2758 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2759 if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone)
2760 ++n_out_peers;
2761 return true;
2762 });
2763 if (n_out_peers >= get_max_out_peers(zone))
2764 return false;
2765 return true;
2766 }
2767 //------------------------------------------------------------------------------------------------------------------------
2768 template<class t_core>
2770 {
2771 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2772 return !sync.owns_lock();
2773 }
2774 //------------------------------------------------------------------------------------------------------------------------
2775 template<class t_core>
2777 {
2778 LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
2779 epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2780 "), score " << score << ", flush_all_spans " << flush_all_spans);
2781
2782 if (score > 0)
2783 m_p2p->add_host_fail(context.m_remote_address, score);
2784
2785 m_block_queue.flush_spans(context.m_connection_id, flush_all_spans);
2786
2787 m_p2p->drop_connection(context);
2788 }
2789 //------------------------------------------------------------------------------------------------------------------------
2790 template<class t_core>
2792 {
2793 return drop_connection_with_score(context, add_fail ? 1 : 0, flush_all_spans);
2794 }
2795 //------------------------------------------------------------------------------------------------------------------------
2796 template<class t_core>
2798 {
2799 m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2800 // This _could be_ outside of strand, so careful on actions
2801 drop_connection(context, true, false);
2802 return true;
2803 });
2804 }
2805 //------------------------------------------------------------------------------------------------------------------------
2806 template<class t_core>
2808 {
2809 MWARNING("dropping connections to " << address.str());
2810
2811 m_p2p->add_host_fail(address, 5);
2812
2813 std::vector<boost::uuids::uuid> drop;
2814 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2815 if (address.is_same_host(cntxt.m_remote_address))
2816 drop.push_back(cntxt.m_connection_id);
2817 return true;
2818 });
2819 for (const boost::uuids::uuid &id: drop)
2820 {
2821 m_block_queue.flush_spans(id, true);
2822 m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2823 // This _could be_ outside of strand, so careful on actions
2824 drop_connection(context, true, false);
2825 return true;
2826 });
2827 }
2828 }
2829 //------------------------------------------------------------------------------------------------------------------------
2830 template<class t_core>
2832 {
2833 uint64_t target = 0;
2834 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2835 if (cntxt.m_state >= cryptonote_connection_context::state_synchronizing && cntxt.m_connection_id != context.m_connection_id)
2836 target = std::max(target, cntxt.m_remote_blockchain_height);
2837 return true;
2838 });
2839 const uint64_t previous_target = m_core.get_target_blockchain_height();
2840 if (target < previous_target)
2841 {
2842 MINFO("Target height decreasing from " << previous_target << " to " << target);
2843 m_core.set_target_blockchain_height(target);
2844 if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
2845 {
2846 MCWARNING("global", "monerod is now disconnected from the network");
2848 }
2849 }
2850
2851 m_block_queue.flush_spans(context.m_connection_id, false);
2852 MLOG_PEER_STATE("closed");
2853 }
2854
2855 //------------------------------------------------------------------------------------------------------------------------
2856 template<class t_core>
2858 {
2859 m_stopping = true;
2860 m_core.stop();
2861 }
2862} // namespace
2863
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:1276
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:2791
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:2710
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:182
void set_p2p_endpoint(nodetool::i_p2p_endpoint< connection_context > *p2p)
Definition cryptonote_protocol_handler.inl:222
int handle_notify_new_transactions(int command, NOTIFY_NEW_TRANSACTIONS::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:878
bool request_missing_objects(cryptonote_connection_context &context, bool check_having_blocks, bool force_next_span=false)
Definition cryptonote_protocol_handler.inl:1992
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:2680
boost::mutex m_buffer_mutex
Definition cryptonote_protocol_handler.h:203
std::string get_peers_overview() const
Definition cryptonote_protocol_handler.inl:2693
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:1639
double get_avg_block_size()
Definition cryptonote_protocol_handler.inl:1013
std::string get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
Definition cryptonote_protocol_handler.inl:1306
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:1968
bool init(const boost::program_options::variables_map &vm)
Definition cryptonote_protocol_handler.inl:196
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:2654
bool request_txpool_complement(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2665
void drop_connections(const epee::net_utils::network_address address)
Definition cryptonote_protocol_handler.inl:2807
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:974
int try_add_next_blocks(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1324
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:1670
bool update_sync_search()
Definition cryptonote_protocol_handler.inl:1696
int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1769
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:2459
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:1800
t_core & m_core
Definition cryptonote_protocol_handler.h:171
size_t get_synchronizing_connections_count()
Definition cryptonote_protocol_handler.inl:2447
size_t skip_unneeded_hashes(cryptonote_connection_context &context, bool check_block_queue) const
Definition cryptonote_protocol_handler.inl:1947
virtual bool relay_block(NOTIFY_NEW_FLUFFY_BLOCK::request &arg, cryptonote_connection_context &exclude_context)
Definition cryptonote_protocol_handler.inl:2627
bool is_busy_syncing()
Definition cryptonote_protocol_handler.inl:2769
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:1661
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:231
boost::posix_time::ptime m_sync_start_time
Definition cryptonote_protocol_handler.h:196
bool check_standby_peers()
Definition cryptonote_protocol_handler.inl:1753
std::list< connection_info > get_connections()
Definition cryptonote_protocol_handler.inl:361
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:216
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:848
bool on_connection_synchronized()
Definition cryptonote_protocol_handler.inl:2375
cryptonote_connection_context connection_context
Definition cryptonote_protocol_handler.h:82
void stop()
Definition cryptonote_protocol_handler.inl:2857
int handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1026
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans)
Definition cryptonote_protocol_handler.inl:2776
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:2751
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:750
void on_connection_close(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2831
bool should_drop_connection(cryptonote_connection_context &context, uint32_t next_stripe)
Definition cryptonote_protocol_handler.inl:1885
tools::PerformanceTimer m_sync_timer
Definition cryptonote_protocol_handler.h:188
void log_connections()
Definition cryptonote_protocol_handler.inl:296
Definition cryptonote_basic.h:205
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:69
static constexpr address_type get_type_id() noexcept
Definition net_utils_base.h:92
constexpr uint16_t port() const noexcept
Definition net_utils_base.h:87
Definition net_utils_base.h:225
bool is_loopback() const
Definition net_utils_base.h:314
std::string str() const
Definition net_utils_base.h:312
address_type get_type_id() const
Definition net_utils_base.h:316
bool is_local() const
Definition net_utils_base.h:315
std::string host_str() const
Definition net_utils_base.h:313
zone get_zone() const
Definition net_utils_base.h:317
const Type & as() const
Definition net_utils_base.h:320
#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:2794
conn start()
#define true
#define false
static void text(MDB_val *v)
Definition mdb_dump.c:58
static int version
Definition mdb_load.c:29
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
static constexpr crypto::hash null_hash
Definition hash.h:102
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:1333
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:1511
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:145
bool parse_and_validate_tx_from_blob(const blobdata_ref &tx_blob, transaction &tx)
Definition cryptonote_format_utils.cpp:224
blobdata block_to_blob(const block &b)
Definition cryptonote_format_utils.cpp:1583
std::string get_protocol_state_string(cryptonote_connection_context::state s)
Definition connection_context.h:123
size_t get_max_tx_size()
Definition cryptonote_basic_impl.cpp:78
void get_blob_hash(const blobdata_ref &blob, crypto::hash &res)
Definition cryptonote_format_utils.cpp:1120
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_tx_base_from_blob(const blobdata_ref &tx_blob, transaction &tx)
Definition cryptonote_format_utils.cpp:235
bool parse_and_validate_block_from_blob(const blobdata_ref &b_blob, block &b, crypto::hash *block_hash)
Definition cryptonote_format_utils.cpp:1557
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
Definition cryptonote_format_utils.h:165
@ 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:135
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:128
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
static std::string peerid_to_string(peerid_type peer_id)
Definition p2p_protocol_defs.h:51
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 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:486
#define LOG_DEBUG_CC(ct, message)
Definition net_utils_base.h:472
#define LOG_PRINT_CCONTEXT_L1(message)
Definition net_utils_base.h:483
#define LOG_PRINT_CCONTEXT_L0(message)
Definition net_utils_base.h:482
#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message)
Definition net_utils_base.h:488
#define LOG_PRINT_CCONTEXT_L2(message)
Definition net_utils_base.h:484
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
static cryptonote::account_public_address address
Definition signature.cpp:38
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:462
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_marked_as_orphaned
Definition verification_context.h:69
bool m_missing_txs
Definition verification_context.h:73
Definition cryptonote_basic.h:475
std::vector< crypto::hash > tx_hashes
Definition cryptonote_basic.h:490
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:102
time_t m_last_send
Definition net_utils_base.h:374
time_t m_last_recv
Definition net_utils_base.h:373
uint64_t m_send_cnt
Definition net_utils_base.h:376
const bool m_is_income
Definition net_utils_base.h:370
const bool m_ssl
Definition net_utils_base.h:372
const boost::uuids::uuid m_connection_id
Definition net_utils_base.h:368
const time_t m_started
Definition net_utils_base.h:371
const network_address m_remote_address
Definition net_utils_base.h:369
double m_current_speed_down
Definition net_utils_base.h:377
double m_current_speed_up
Definition net_utils_base.h:378
uint64_t m_recv_cnt
Definition net_utils_base.h:375
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