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 tx_hash = cryptonote::get_pruned_transaction_hash(tx, tx_entry.prunable_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(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 uint64_t block_process_time_full = 0, transactions_process_time_full = 0;
1479 size_t num_txs = 0, blockidx = 0;
1480 for(const block_complete_entry& block_entry: blocks)
1481 {
1482 if (m_stopping)
1483 {
1484 m_core.cleanup_handle_incoming_blocks();
1485 return 1;
1486 }
1487
1488 // process transactions
1489 TIME_MEASURE_START(transactions_process_time);
1490 num_txs += block_entry.txs.size();
1491
1492 pool_supplement block_txs;
1493 if (!make_full_pool_supplement_from_block_entry(block_entry, block_txs))
1494 {
1495 drop_connections(span_origin);
1496 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1497 LOG_ERROR_CCONTEXT("transaction parsing failed for 1 or more txs in NOTIFY_RESPONSE_GET_OBJECTS,"
1498 "dropping connections");
1499 drop_connection(context, false, true);
1500 return 1;
1501 }))
1502 LOG_ERROR_CCONTEXT("span connection id not found");
1503
1504 if (!m_core.cleanup_handle_incoming_blocks())
1505 {
1506 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1507 return 1;
1508 }
1509 // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
1510 m_block_queue.remove_spans(span_connection_id, start_height);
1511 return 1;
1512 }
1513 TIME_MEASURE_FINISH(transactions_process_time);
1514 transactions_process_time_full += transactions_process_time;
1515
1516 // process block
1517
1518 TIME_MEASURE_START(block_process_time);
1520
1521 m_core.handle_incoming_block(block_entry.block,
1522 pblocks.empty() ? NULL : &pblocks[blockidx],
1523 bvc,
1524 block_txs,
1525 false); // <--- process block
1526
1527 if(bvc.m_verifivation_failed)
1528 {
1529 drop_connections(span_origin);
1530 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1531 LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection");
1532 drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true);
1533 return 1;
1534 }))
1535 LOG_ERROR_CCONTEXT("span connection id not found");
1536
1537 if (!m_core.cleanup_handle_incoming_blocks())
1538 {
1539 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1540 return 1;
1541 }
1542
1543 // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
1544 m_block_queue.remove_spans(span_connection_id, start_height);
1545 return 1;
1546 }
1547 if(bvc.m_marked_as_orphaned)
1548 {
1549 drop_connections(span_origin);
1550 if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
1551 LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection");
1552 drop_connection(context, true, true);
1553 return 1;
1554 }))
1555 LOG_ERROR_CCONTEXT("span connection id not found");
1556
1557 if (!m_core.cleanup_handle_incoming_blocks())
1558 {
1559 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1560 return 1;
1561 }
1562
1563 // in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
1564 m_block_queue.remove_spans(span_connection_id, start_height);
1565 return 1;
1566 }
1567
1568 TIME_MEASURE_FINISH(block_process_time);
1569 block_process_time_full += block_process_time;
1570 ++blockidx;
1571
1572 } // each download block
1573
1574 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");
1575
1576 if (!m_core.cleanup_handle_incoming_blocks())
1577 {
1578 LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
1579 return 1;
1580 }
1581
1582 m_block_queue.remove_spans(span_connection_id, start_height);
1583
1584 const uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
1585 if (current_blockchain_height > previous_height)
1586 {
1587 const uint64_t target_blockchain_height = m_core.get_target_blockchain_height();
1588 const boost::posix_time::time_duration dt = boost::posix_time::microsec_clock::universal_time() - start;
1589 std::string progress_message = "";
1590 if (current_blockchain_height < target_blockchain_height)
1591 {
1592 uint64_t completion_percent = (current_blockchain_height * 100 / target_blockchain_height);
1593 if (completion_percent == 100) // never show 100% if not actually up to date
1594 completion_percent = 99;
1595 progress_message = " (" + std::to_string(completion_percent) + "%, "
1596 + std::to_string(target_blockchain_height - current_blockchain_height) + " left";
1597 std::string time_message = get_periodic_sync_estimate(current_blockchain_height, target_blockchain_height);
1598 if (!time_message.empty())
1599 {
1600 uint64_t total_blocks_to_sync = target_blockchain_height - m_sync_start_height;
1601 uint64_t total_blocks_synced = current_blockchain_height - m_sync_start_height;
1602 progress_message += ", " + std::to_string(total_blocks_synced * 100 / total_blocks_to_sync) + "% of total synced";
1603 progress_message += ", estimated " + time_message + " left";
1604 }
1605 progress_message += ")";
1606 }
1607 const uint32_t previous_stripe = tools::get_pruning_stripe(previous_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1608 const uint32_t current_stripe = tools::get_pruning_stripe(current_blockchain_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
1609 std::string timing_message = "";
1610 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
1611 timing_message = std::string(" (") + std::to_string(dt.total_microseconds()/1e6) + " sec, "
1612 + std::to_string((current_blockchain_height - previous_height) * 1e6 / dt.total_microseconds())
1613 + " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued in "
1614 + std::to_string(m_block_queue.get_num_filled_spans()) + " spans, stripe "
1615 + std::to_string(previous_stripe) + " -> " + std::to_string(current_stripe);
1616 if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info"))
1617 timing_message += std::string(": ") + m_block_queue.get_overview(current_blockchain_height);
1618 MGINFO_YELLOW("Synced " << current_blockchain_height << "/" << target_blockchain_height
1619 << progress_message << timing_message);
1620 if (previous_stripe != current_stripe)
1621 notify_new_stripe(context, current_stripe);
1622 }
1623 }
1624 }
1625
1626 MLOG_PEER_STATE("stopping adding blocks");
1627
1628 if (should_download_next_span(context, false))
1629 {
1630 force_next_span = true;
1631 }
1632 else if (should_drop_connection(context, get_next_needed_pruning_stripe().first))
1633 {
1634 if (!context.m_is_income)
1635 {
1636 m_p2p->add_used_stripe_peer(context);
1637 drop_connection(context, false, false);
1638 }
1639 return 1;
1640 }
1641 }
1642
1643skip:
1644 if (!request_missing_objects(context, true, force_next_span))
1645 {
1646 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
1647 drop_connection(context, false, false);
1648 return 1;
1649 }
1650 return 1;
1651 }
1652 //------------------------------------------------------------------------------------------------------------------------
1653 template<class t_core>
1655 {
1656 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1657 {
1658 if (cntxt.m_connection_id == context.m_connection_id)
1659 return true;
1660 if (context.m_state == cryptonote_connection_context::state_normal)
1661 {
1662 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1663 if (stripe && peer_stripe && peer_stripe != stripe)
1664 return true;
1665 context.m_new_stripe_notification = true;
1666 LOG_PRINT_CCONTEXT_L2("requesting callback");
1667 ++context.m_callback_request_count;
1668 m_p2p->request_callback(context);
1669 MLOG_PEER_STATE("requesting callback");
1670 }
1671 return true;
1672 });
1673 }
1674 //------------------------------------------------------------------------------------------------------------------------
1675 template<class t_core>
1683 //------------------------------------------------------------------------------------------------------------------------
1684 template<class t_core>
1686 {
1687 MTRACE("Checking for idle peers...");
1688 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1689 {
1690 if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
1691 {
1692 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1693 const boost::posix_time::time_duration dt = now - context.m_last_request_time;
1694 const auto ms = dt.total_microseconds();
1695 if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
1696 {
1697 context.m_idle_peer_notification = true;
1698 LOG_PRINT_CCONTEXT_L2("requesting callback");
1699 ++context.m_callback_request_count;
1700 m_p2p->request_callback(context);
1701 MLOG_PEER_STATE("requesting callback");
1702 }
1703 }
1704 return true;
1705 });
1706
1707 return true;
1708 }
1709 //------------------------------------------------------------------------------------------------------------------------
1710 template<class t_core>
1712 {
1713 const uint64_t target = m_core.get_target_blockchain_height();
1714 const uint64_t height = m_core.get_current_blockchain_height();
1715 if (target > height) // if we're not synced yet, don't do it
1716 return true;
1717
1718 MTRACE("Checking for outgoing syncing peers...");
1719 std::unordered_map<epee::net_utils::zone, unsigned> n_syncing, n_synced;
1720 std::unordered_map<epee::net_utils::zone, boost::uuids::uuid> last_synced_peer_id;
1721 std::vector<epee::net_utils::zone> zones;
1722 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1723 {
1724 if (!peer_id || context.m_is_income) // only consider connected outgoing peers
1725 return true;
1726
1727 const epee::net_utils::zone zone = context.m_remote_address.get_zone();
1728 if (n_syncing.find(zone) == n_syncing.end())
1729 {
1730 n_syncing[zone] = 0;
1731 n_synced[zone] = 0;
1732 last_synced_peer_id[zone] = boost::uuids::nil_uuid();
1733 zones.push_back(zone);
1734 }
1735
1737 ++n_syncing[zone];
1738 if (context.m_state == cryptonote_connection_context::state_normal)
1739 {
1740 ++n_synced[zone];
1741 if (!context.m_anchor)
1742 last_synced_peer_id[zone] = context.m_connection_id;
1743 }
1744 return true;
1745 });
1746
1747 for (const auto& zone : zones)
1748 {
1749 const unsigned int max_out_peers = get_max_out_peers(zone);
1750 MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1751
1752 // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor
1753 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())
1754 {
1755 if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1756 MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers");
1757 drop_connection(ctx, false, false);
1758 return true;
1759 }))
1760 MDEBUG("Failed to find peer we wanted to drop");
1761 }
1762 }
1763
1764 return true;
1765 }
1766 //------------------------------------------------------------------------------------------------------------------------
1767 template<class t_core>
1769 {
1770 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
1771 {
1772 if (context.m_state == cryptonote_connection_context::state_standby)
1773 {
1774 LOG_PRINT_CCONTEXT_L2("requesting callback");
1775 ++context.m_callback_request_count;
1776 m_p2p->request_callback(context);
1777 }
1778 return true;
1779 });
1780 return true;
1781 }
1782 //------------------------------------------------------------------------------------------------------------------------
1783 template<class t_core>
1785 {
1786 MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
1788 {
1789 LOG_ERROR_CCONTEXT("Requested chain before handshake, dropping connection");
1790 drop_connection(context, false, false);
1791 return 1;
1792 }
1794 if(!m_core.find_blockchain_supplement(arg.block_ids, !arg.prune, r))
1795 {
1796 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
1797 return 1;
1798 }
1799 if (r.m_block_ids.size() >= 2)
1800 {
1802 if (!m_core.get_block_by_hash(r.m_block_ids[1], b))
1803 {
1804 LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN: first block not found");
1805 return 1;
1806 }
1807 r.first_block = cryptonote::block_to_blob(b);
1808 }
1809 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());
1811 return 1;
1812 }
1813 //------------------------------------------------------------------------------------------------------------------------
1814 template<class t_core>
1816 {
1817 std::vector<crypto::hash> hashes;
1818 boost::posix_time::ptime request_time;
1819 boost::uuids::uuid connection_id;
1820 bool filled;
1821
1822 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
1823 if (context.m_remote_blockchain_height <= blockchain_height)
1824 return false;
1825 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
1826 const bool has_next_block = tools::has_unpruned_block(blockchain_height, context.m_remote_blockchain_height, context.m_pruning_seed);
1827 if (has_next_block)
1828 {
1829 if (!m_block_queue.has_next_span(blockchain_height, filled, request_time, connection_id))
1830 {
1831 MDEBUG(context << " we should download it as no peer reserved it");
1832 return true;
1833 }
1834 if (!filled)
1835 {
1836 const long dt = (now - request_time).total_microseconds();
1838 {
1839 MDEBUG(context << " we should download it as it's not been received yet after " << dt/1e6);
1840 return true;
1841 }
1842
1843 // in standby, be ready to double download early since we're idling anyway
1844 // let the fastest peer trigger first
1845 const double dl_speed = context.m_max_speed_down;
1846 if (standby && dt >= REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY && dl_speed > 0)
1847 {
1848 bool download = false;
1849 if (m_p2p->for_connection(connection_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
1850 const time_t nowt = time(NULL);
1851 const time_t time_since_last_recv = nowt - ctx.m_last_recv;
1852 const float last_activity = std::min((float)time_since_last_recv, dt/1e6f);
1853 const bool stalled = last_activity > LAST_ACTIVITY_STALL_THRESHOLD;
1854 if (stalled)
1855 {
1856 MDEBUG(context << " we should download it as the downloading peer is stalling for " << nowt - ctx.m_last_recv << " seconds");
1857 download = true;
1858 return true;
1859 }
1860
1861 // estimate the standby peer can give us 80% of its max speed
1862 // and let it download if that speed is > N times as fast as the current one
1863 // N starts at 10 after REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD_STANDBY,
1864 // decreases to 1.25 at REQUEST_NEXT_SCHEDULED_SPAN_THRESHOLD,
1865 // so that at times goes without the download being done, a retry becomes easier
1866 const float max_multiplier = 10.f;
1867 const float min_multiplier = 1.25f;
1868 float multiplier = max_multiplier;
1870 {
1871 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);
1872 multiplier = std::min(max_multiplier, std::max(min_multiplier, multiplier));
1873 }
1874 if (dl_speed * .8f > ctx.m_current_speed_down * multiplier)
1875 {
1876 MDEBUG(context << " we should download it as we are substantially faster (" << dl_speed << " vs "
1877 << ctx.m_current_speed_down << ", multiplier " << multiplier << " after " << dt/1e6 << " seconds)");
1878 download = true;
1879 return true;
1880 }
1881 return true;
1882 }))
1883 {
1884 if (download)
1885 return true;
1886 }
1887 else
1888 {
1889 MWARNING(context << " we should download it as the downloading peer is unexpectedly not known to us");
1890 return true;
1891 }
1892 }
1893 }
1894 }
1895
1896 return false;
1897 }
1898 //------------------------------------------------------------------------------------------------------------------------
1899 template<class t_core>
1901 {
1902 if (context.m_anchor)
1903 {
1904 MDEBUG(context << "This is an anchor peer, not dropping");
1905 return false;
1906 }
1907 if (context.m_pruning_seed == 0)
1908 {
1909 MDEBUG(context << "This peer is not striped, not dropping");
1910 return false;
1911 }
1912
1913 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
1914 if (next_stripe == peer_stripe)
1915 {
1916 MDEBUG(context << "This peer has needed stripe " << peer_stripe << ", not dropping");
1917 return false;
1918 }
1919 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1920 if (m_sync_pruned_blocks && local_stripe && next_stripe != local_stripe)
1921 {
1922 MDEBUG(context << "We can sync pruned blocks off this peer, not dropping");
1923 return false;
1924 }
1925
1926 if (!context.m_needed_objects.empty())
1927 {
1928 const uint64_t next_available_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
1929 if (tools::has_unpruned_block(next_available_block_height, context.m_remote_blockchain_height, context.m_pruning_seed))
1930 {
1931 MDEBUG(context << "This peer has unpruned next block at height " << next_available_block_height << ", not dropping");
1932 return false;
1933 }
1934 }
1935
1936 if (next_stripe > 0)
1937 {
1938 unsigned int n_out_peers = 0, n_peers_on_next_stripe = 0;
1939 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
1940 if (!ctx.m_is_income)
1941 ++n_out_peers;
1943 ++n_peers_on_next_stripe;
1944 return true;
1945 });
1946 // TODO: investigate tallying by zone and comparing to max out peers by zone
1947 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
1948 const uint32_t distance = (peer_stripe + (1<<CRYPTONOTE_PRUNING_LOG_STRIPES) - next_stripe) % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
1949 if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2)
1950 {
1951 MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers ("
1952 << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe <<
1953 " is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space");
1954 return true;
1955 }
1956 }
1957 MDEBUG(context << "End of checks, not dropping");
1958 return false;
1959 }
1960 //------------------------------------------------------------------------------------------------------------------------
1961 template<class t_core>
1963 {
1964 // take out blocks we already have
1965 size_t skip = 0;
1966 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))))
1967 {
1968 // if we're popping the last hash, record it so we can ask again from that hash,
1969 // this prevents never being able to progress on peers we get old hash lists from
1970 if (skip + 1 == context.m_needed_objects.size())
1971 context.m_last_known_hash = context.m_needed_objects[skip].first;
1972 ++skip;
1973 }
1974 if (skip > 0)
1975 {
1976 MDEBUG(context << "skipping " << skip << "/" << context.m_needed_objects.size() << " blocks");
1977 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
1978 }
1979 return skip;
1980 }
1981 //------------------------------------------------------------------------------------------------------------------------
1982 template<class t_core>
1983 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
1984 {
1986 return false;
1987 if (!m_core.is_within_compiled_block_hash_area(first_block_height + nblocks - 1))
1988 return false;
1989 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
1990 if (local_stripe == 0)
1991 return false;
1992 // don't request pre-bulletprooof pruned blocks, we can't reconstruct their weight (yet)
1993 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(HF_VERSION_SMALLER_BP + 1);
1994 if (first_block_height < bp_fork_height)
1995 return false;
1996 // assumes the span size is less or equal to the stripe size
1997 bool full_data_needed = tools::get_pruning_stripe(first_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe
1998 || tools::get_pruning_stripe(first_block_height + nblocks - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES) == local_stripe;
1999 if (full_data_needed)
2000 return false;
2001 if (check_block_weights && !m_core.has_block_weights(first_block_height, nblocks))
2002 return false;
2003 return true;
2004 }
2005 //------------------------------------------------------------------------------------------------------------------------
2006 template<class t_core>
2007 bool t_cryptonote_protocol_handler<t_core>::request_missing_objects(cryptonote_connection_context& context, bool check_having_blocks, bool force_next_span)
2008 {
2009 // flush stale spans
2010 std::set<boost::uuids::uuid> live_connections;
2011 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2012 live_connections.insert(context.m_connection_id);
2013 return true;
2014 });
2015 m_block_queue.flush_stale_spans(live_connections);
2016
2017 // if we don't need to get next span, and the block queue is full enough, wait a bit
2018 if (!force_next_span)
2019 {
2020 do
2021 {
2022 size_t nspans = m_block_queue.get_num_filled_spans();
2023 size_t size = m_block_queue.get_data_size();
2024 const uint64_t bc_height = m_core.get_current_blockchain_height();
2025 const auto next_needed_pruning_stripe = get_next_needed_pruning_stripe();
2026 const uint32_t add_stripe = tools::get_pruning_stripe(bc_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2027 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2028 const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
2029 const size_t block_queue_size_threshold = m_block_download_max_size ? m_block_download_max_size : BLOCK_QUEUE_SIZE_THRESHOLD;
2030 bool queue_proceed = nspans < BLOCK_QUEUE_NSPANS_THRESHOLD || size < block_queue_size_threshold;
2031 // get rid of blocks we already requested, or already have
2032 if (skip_unneeded_hashes(context, true) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2033 {
2034 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(bc_height))
2035 {
2036 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2037 return false;
2038 }
2039 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2040 context.set_state_normal();
2041 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2043 return true;
2044 }
2045 uint64_t next_needed_height = m_block_queue.get_next_needed_height(bc_height);
2046 uint64_t next_block_height;
2047 if (context.m_needed_objects.empty())
2048 next_block_height = next_needed_height;
2049 else
2050 next_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2051 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);
2052 bool stripe_proceed_secondary = tools::has_unpruned_block(next_block_height, context.m_remote_blockchain_height, context.m_pruning_seed);
2053 bool proceed = stripe_proceed_main || (queue_proceed && stripe_proceed_secondary);
2054 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)))
2055 {
2056 if (!context.m_is_income)
2057 m_p2p->add_used_stripe_peer(context);
2058 return false; // drop outgoing connections
2059 }
2060
2061 MDEBUG(context << "proceed " << proceed << " (queue " << queue_proceed << ", stripe " << stripe_proceed_main << "/" <<
2062 stripe_proceed_secondary << "), " << next_needed_pruning_stripe.first << "-" << next_needed_pruning_stripe.second <<
2063 " needed, bc add stripe " << add_stripe << ", we have " << peer_stripe << "), bc_height " << bc_height);
2064 MDEBUG(context << " - next_block_height " << next_block_height << ", seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2065 ", next_needed_height "<< next_needed_height);
2066 MDEBUG(context << " - last_response_height " << context.m_last_response_height << ", m_needed_objects size " << context.m_needed_objects.size());
2067
2068 // if we're waiting for next span, try to get it before unblocking threads below,
2069 // or a runaway downloading of future spans might happen
2070 if (stripe_proceed_main && should_download_next_span(context, true))
2071 {
2072 MDEBUG(context << " we should try for that next span too, we think we could get it faster, resuming");
2073 force_next_span = true;
2074 MLOG_PEER_STATE("resuming");
2075 break;
2076 }
2077
2078 if (proceed)
2079 {
2080 if (context.m_state != cryptonote_connection_context::state_standby)
2081 {
2082 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", resuming");
2083 MLOG_PEER_STATE("resuming");
2084 }
2085 break;
2086 }
2087
2088 // this one triggers if all threads are in standby, which should not happen,
2089 // but happened at least once, so we unblock at least one thread if so
2090 boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2091 if (sync.owns_lock())
2092 {
2093 bool filled = false;
2094 boost::posix_time::ptime time;
2095 boost::uuids::uuid connection_id;
2096 if (m_block_queue.has_next_span(m_core.get_current_blockchain_height(), filled, time, connection_id) && filled)
2097 {
2098 LOG_DEBUG_CC(context, "No other thread is adding blocks, and next span needed is ready, resuming");
2099 MLOG_PEER_STATE("resuming");
2101 ++context.m_callback_request_count;
2102 m_p2p->request_callback(context);
2103 return true;
2104 }
2105 else
2106 {
2107 sync.unlock();
2108
2109 // if this has gone on for too long, drop incoming connection to guard against some wedge state
2110 if (!context.m_is_income)
2111 {
2112 const uint64_t now = tools::get_tick_count();
2113 const uint64_t dt = now - m_last_add_end_time;
2115 {
2116 MDEBUG(context << "ns " << tools::ticks_to_ns(dt) << " from " << m_last_add_end_time << " and " << now);
2117 MDEBUG(context << "Block addition seems to have wedged, dropping connection");
2118 return false;
2119 }
2120 }
2121 }
2122 }
2123
2124 if (context.m_state != cryptonote_connection_context::state_standby)
2125 {
2126 if (!queue_proceed)
2127 LOG_DEBUG_CC(context, "Block queue is " << nspans << " and " << size << ", pausing");
2128 else if (!stripe_proceed_main && !stripe_proceed_secondary)
2129 LOG_DEBUG_CC(context, "We do not have the stripe required to download another block, pausing");
2131 MLOG_PEER_STATE("pausing");
2132 }
2133
2134 return true;
2135 } while(0);
2137 }
2138
2139 MDEBUG(context << " request_missing_objects: check " << check_having_blocks << ", force_next_span " << force_next_span
2140 << ", m_needed_objects " << context.m_needed_objects.size() << " lrh " << context.m_last_response_height << ", chain "
2141 << m_core.get_current_blockchain_height() << ", pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed));
2142 if(context.m_needed_objects.size() || force_next_span)
2143 {
2144 //we know objects that we need, request this objects
2146 bool is_next = false;
2147 size_t count = 0;
2148 const size_t count_limit = m_core.get_block_sync_size(m_core.get_current_blockchain_height());
2149 std::pair<uint64_t, uint64_t> span = std::make_pair(0, 0);
2150 if (force_next_span)
2151 {
2152 if (span.second == 0)
2153 {
2154 std::vector<crypto::hash> hashes;
2155 boost::uuids::uuid span_connection_id;
2156 boost::posix_time::ptime time;
2157 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2158 if (span.second > 0)
2159 {
2160 is_next = true;
2161 req.blocks.reserve(hashes.size());
2162 for (const auto &hash: hashes)
2163 {
2164 req.blocks.push_back(hash);
2165 context.m_requested_objects.insert(hash);
2166 }
2167 m_block_queue.reset_next_span_time();
2168 }
2169 }
2170 }
2171 if (span.second == 0)
2172 {
2173 MDEBUG(context << " span size is 0");
2174 if (context.m_last_response_height + 1 < context.m_needed_objects.size())
2175 {
2176 MERROR(context << " ERROR: inconsistent context: lrh " << context.m_last_response_height << ", nos " << context.m_needed_objects.size());
2177 context.m_needed_objects.clear();
2178 context.m_last_response_height = 0;
2179 goto skip;
2180 }
2181 if (skip_unneeded_hashes(context, false) && context.m_needed_objects.empty() && context.m_num_requested == 0)
2182 {
2183 if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(m_core.get_current_blockchain_height()))
2184 {
2185 MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
2186 return false;
2187 }
2188 MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
2189 context.set_state_normal();
2190 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2192 return true;
2193 }
2194
2195 const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2196 static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
2197 bool sync_pruned_blocks = m_sync_pruned_blocks && first_block_height >= bp_fork_height && m_core.get_blockchain_pruning_seed();
2198 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);
2199 MDEBUG(context << " span from " << first_block_height << ": " << span.first << "/" << span.second);
2200 if (span.second > 0)
2201 {
2202 const uint32_t stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2203 if (context.m_pruning_seed && stripe != tools::get_pruning_stripe(context.m_pruning_seed))
2204 {
2205 MDEBUG(context << " starting early on next seed (" << span.first << " with stripe " << stripe <<
2206 ", context seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << ")");
2207 }
2208 }
2209 }
2210 if (span.second == 0 && !force_next_span)
2211 {
2212 MDEBUG(context << " still no span reserved, we may be in the corner case of next span scheduled and everything else scheduled/filled");
2213 std::vector<crypto::hash> hashes;
2214 boost::uuids::uuid span_connection_id;
2215 boost::posix_time::ptime time;
2216 span = m_block_queue.get_next_span_if_scheduled(hashes, span_connection_id, time);
2217 if (span.second > 0 && !tools::has_unpruned_block(span.first, context.m_remote_blockchain_height, context.m_pruning_seed))
2218 span = std::make_pair(0, 0);
2219 if (span.second > 0)
2220 {
2221 is_next = true;
2222 req.blocks.reserve(hashes.size());
2223 for (const auto &hash: hashes)
2224 {
2225 req.blocks.push_back(hash);
2226 ++count;
2227 context.m_requested_objects.insert(hash);
2228 // that's atrocious O(n) wise, but this is rare
2229 auto i = std::find_if(context.m_needed_objects.begin(), context.m_needed_objects.end(),
2230 [&hash](const std::pair<crypto::hash, uint64_t> &o) { return o.first == hash; });
2231 if (i != context.m_needed_objects.end())
2232 context.m_needed_objects.erase(i);
2233 }
2234 }
2235 }
2236 MDEBUG(context << " span: " << span.first << "/" << span.second << " (" << span.first << " - " << (span.first + span.second - 1) << ")");
2237 if (span.second > 0)
2238 {
2239 if (!is_next)
2240 {
2241 const uint64_t first_context_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
2242 uint64_t skip = span.first - first_context_block_height;
2243 if (skip > context.m_needed_objects.size())
2244 {
2245 MERROR("ERROR: skip " << skip << ", m_needed_objects " << context.m_needed_objects.size() << ", first_context_block_height" << first_context_block_height);
2246 return false;
2247 }
2248 if (skip > 0)
2249 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
2250 if (context.m_needed_objects.size() < span.second)
2251 {
2252 MERROR("ERROR: span " << span.first << "/" << span.second << ", m_needed_objects " << context.m_needed_objects.size());
2253 return false;
2254 }
2255
2256 req.blocks.reserve(req.blocks.size() + span.second);
2257 for (size_t n = 0; n < span.second; ++n)
2258 {
2259 req.blocks.push_back(context.m_needed_objects[n].first);
2260 ++count;
2261 context.m_requested_objects.insert(context.m_needed_objects[n].first);
2262 }
2263 context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + span.second, context.m_needed_objects.end());
2264 }
2265
2266 req.prune = should_ask_for_pruned_data(context, span.first, span.second, true);
2267
2268 // if we need to ask for full data and that peer does not have the right stripe, we can't ask it
2269 if (!req.prune && context.m_pruning_seed)
2270 {
2271 const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
2272 const uint32_t first_stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2273 const uint32_t last_stripe = tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2274 if (((first_stripe && peer_stripe != first_stripe) || (last_stripe && peer_stripe != last_stripe)) && !m_sync_pruned_blocks)
2275 {
2276 MDEBUG(context << "We need full data, but the peer does not have it, dropping peer");
2277 return false;
2278 }
2279 }
2280 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2281 context.m_expect_height = span.first;
2282 context.m_expect_response = NOTIFY_RESPONSE_GET_OBJECTS::ID;
2283 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_GET_OBJECTS: blocks.size()=" << req.blocks.size()
2284 << "requested blocks count=" << count << " / " << count_limit << " from " << span.first << ", first hash " << req.blocks.front());
2285 //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());
2286
2287 MDEBUG("Asking for " << (req.prune ? "pruned" : "full") << " data, start/end "
2288 << tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2289 << "/" << tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
2290 << ", ours " << tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed()) << ", peer stripe " << tools::get_pruning_stripe(context.m_pruning_seed));
2291
2292 context.m_num_requested += req.blocks.size();
2294 MLOG_PEER_STATE("requesting objects");
2295 return true;
2296 }
2297
2298 // we can do nothing, so drop this peer to make room for others unless we think we've downloaded all we need
2299 const uint64_t blockchain_height = m_core.get_current_blockchain_height();
2300 if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
2301 {
2302 context.set_state_normal();
2303 MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
2304 return true;
2305 }
2306 MLOG_PEER_STATE("We can download nothing from this peer, dropping");
2307 return false;
2308 }
2309
2310skip:
2311 context.m_needed_objects.clear();
2312
2313 // we might have been called from the "received chain entry" handler, and end up
2314 // here because we can't use any of those blocks (maybe because all of them are
2315 // actually already requested). In this case, if we can add blocks instead, do so
2316 if (m_core.get_current_blockchain_height() < m_core.get_target_blockchain_height())
2317 {
2318 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2319 if (sync.owns_lock())
2320 {
2321 uint64_t start_height;
2322 std::vector<cryptonote::block_complete_entry> blocks;
2323 boost::uuids::uuid span_connection_id;
2325 if (m_block_queue.get_next_span(start_height, blocks, span_connection_id, span_origin, true))
2326 {
2327 LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
2328 MLOG_PEER_STATE("will try to add blocks next");
2330 ++context.m_callback_request_count;
2331 m_p2p->request_callback(context);
2332 return true;
2333 }
2334 }
2335 }
2336
2337 if(context.m_last_response_height < context.m_remote_blockchain_height-1)
2338 {//we have to fetch more objects ids, request blockchain entry
2339
2341 m_core.get_short_chain_history(r.block_ids, context.m_expect_height);
2342 CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
2343
2344 // we'll want to start off from where we are on that peer, which may not be added yet
2345 if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
2346 {
2347 context.m_expect_height = std::numeric_limits<uint64_t>::max();
2348 r.block_ids.push_front(context.m_last_known_hash);
2349 }
2350
2351 handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
2352 r.prune = m_sync_pruned_blocks;
2353
2354 //std::string blob; // for calculate size of request
2355 //epee::serialization::store_t_to_binary(r, blob);
2356 //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());
2357 //LOG_PRINT_CCONTEXT_L1("r = " << 200);
2358
2359 context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
2360 context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
2361 MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
2363 MLOG_PEER_STATE("requesting chain");
2364 }else
2365 {
2366 CHECK_AND_ASSERT_MES(context.m_last_response_height == context.m_remote_blockchain_height-1
2367 && !context.m_needed_objects.size()
2368 && !context.m_requested_objects.size(), false, "request_missing_blocks final condition failed!"
2369 << "\r\nm_last_response_height=" << context.m_last_response_height
2370 << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height
2371 << "\r\nm_needed_objects.size()=" << context.m_needed_objects.size()
2372 << "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
2373 << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
2374
2375 context.set_state_normal();
2376 if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
2377 {
2378 if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
2380 }
2381 else
2382 {
2383 MINFO(context << " we've reached this peer's blockchain height (theirs " << context.m_remote_blockchain_height << ", our target " << m_core.get_target_blockchain_height());
2384 }
2385 }
2386 return true;
2387 }
2388 //------------------------------------------------------------------------------------------------------------------------
2389 template<class t_core>
2391 {
2392 bool val_expected = false;
2393 uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
2394 if(!m_core.is_within_compiled_block_hash_area(current_blockchain_height) && m_synchronized.compare_exchange_strong(val_expected, true))
2395 {
2396 if ((current_blockchain_height > m_sync_start_height) && (m_sync_spans_downloaded > 0))
2397 {
2398 uint64_t synced_blocks = current_blockchain_height - m_sync_start_height;
2399 // Report only after syncing an "interesting" number of blocks:
2400 if (synced_blocks > 20)
2401 {
2402 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2403 uint64_t synced_seconds = (now - m_sync_start_time).total_seconds();
2404 if (synced_seconds == 0)
2405 {
2406 synced_seconds = 1;
2407 }
2408 float blocks_per_second = (1000 * synced_blocks / synced_seconds) / 1000.0f;
2409 MGINFO_YELLOW("Synced " << synced_blocks << " blocks in "
2410 << tools::get_human_readable_timespan(synced_seconds) << " (" << blocks_per_second << " blocks per second)");
2411 }
2412 }
2413 MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
2414 << "You are now synchronized with the network. You may now start monero-wallet-cli." << ENDL
2415 << ENDL
2416 << "Use the \"help\" command to see the list of available commands." << ENDL
2417 << "**********************************************************************");
2418 m_sync_timer.pause();
2419 if (ELPP->vRegistry()->allowed(el::Level::Info, "sync-info"))
2420 {
2421 const uint64_t sync_time = m_sync_timer.value();
2422 const uint64_t add_time = m_add_timer.value();
2423 if (sync_time && add_time)
2424 {
2425 MCLOG_YELLOW(el::Level::Info, "sync-info", "Sync time: " << sync_time/1e9/60 << " min, idle time " <<
2426 (100.f * (1.0f - add_time / (float)sync_time)) << "%" << ", " <<
2427 (10 * m_sync_download_objects_size / 1024 / 1024) / 10.f << " + " <<
2428 (10 * m_sync_download_chain_size / 1024 / 1024) / 10.f << " MB downloaded, " <<
2429 100.0f * m_sync_old_spans_downloaded / m_sync_spans_downloaded << "% old spans, " <<
2430 100.0f * m_sync_bad_spans_downloaded / m_sync_spans_downloaded << "% bad spans");
2431 }
2432 }
2433 m_core.on_synchronized();
2434 }
2435 m_core.safesyncmode(true);
2436 m_p2p->clear_used_stripe_peers();
2437
2438 // ask for txpool complement from any suitable node if we did not yet
2439 val_expected = true;
2440 if (m_ask_for_txpool_complement.compare_exchange_strong(val_expected, false))
2441 {
2442 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
2443 {
2445 {
2446 MDEBUG(context << "not ready, ignoring");
2447 return true;
2448 }
2449 if (!request_txpool_complement(context))
2450 {
2451 MERROR(context << "Failed to request txpool complement");
2452 return true;
2453 }
2454 return false;
2455 });
2456 }
2457
2458 return true;
2459 }
2460 //------------------------------------------------------------------------------------------------------------------------
2461 template<class t_core>
2463 {
2464 size_t count = 0;
2465 m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2467 ++count;
2468 return true;
2469 });
2470 return count;
2471 }
2472 //------------------------------------------------------------------------------------------------------------------------
2473 template<class t_core>
2475 {
2476 MLOG_P2P_MESSAGE("Received NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
2477 << ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height << ", expect height=" << context.m_expect_height);
2478 MLOG_PEER_STATE("received chain");
2479
2480 if (context.m_expect_response != NOTIFY_RESPONSE_CHAIN_ENTRY::ID)
2481 {
2482 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY out of the blue, dropping connection");
2483 drop_connection(context, true, false);
2484 return 1;
2485 }
2486 context.m_expect_response = 0;
2487 if (arg.start_height + 1 > context.m_expect_height) // we expect an overlapping block
2488 {
2489 LOG_ERROR_CCONTEXT("Got NOTIFY_RESPONSE_CHAIN_ENTRY past expected height, dropping connection");
2490 drop_connection(context, true, false);
2491 return 1;
2492 }
2493
2494 context.m_last_request_time = boost::date_time::not_a_date_time;
2495
2496 m_sync_download_chain_size += arg.m_block_ids.size() * sizeof(crypto::hash);
2497
2498 if(!arg.m_block_ids.size())
2499 {
2500 LOG_ERROR_CCONTEXT("sent empty m_block_ids, dropping connection");
2501 drop_connection(context, true, false);
2502 return 1;
2503 }
2504 if (arg.total_height < arg.m_block_ids.size() || arg.start_height > arg.total_height - arg.m_block_ids.size())
2505 {
2506 LOG_ERROR_CCONTEXT("sent invalid start/nblocks/height, dropping connection");
2507 drop_connection(context, true, false);
2508 return 1;
2509 }
2510 if (!arg.m_block_weights.empty() && arg.m_block_weights.size() != arg.m_block_ids.size())
2511 {
2512 LOG_ERROR_CCONTEXT("sent invalid block weight array, dropping connection");
2513 drop_connection(context, true, false);
2514 return 1;
2515 }
2516 MDEBUG(context << "first block hash " << arg.m_block_ids.front() << ", last " << arg.m_block_ids.back());
2517
2518 if (arg.total_height >= CRYPTONOTE_MAX_BLOCK_NUMBER || arg.m_block_ids.size() > BLOCKS_IDS_SYNCHRONIZING_MAX_COUNT)
2519 {
2520 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with total_height=" << arg.total_height << " and block_ids=" << arg.m_block_ids.size());
2521 drop_connection(context, false, false);
2522 return 1;
2523 }
2524 if (arg.total_height < context.m_remote_blockchain_height)
2525 {
2526 MINFO(context << "Claims " << arg.total_height << ", claimed " << context.m_remote_blockchain_height << " before");
2527 hit_score(context, 1);
2528 }
2529 context.m_remote_blockchain_height = arg.total_height;
2530 context.m_last_response_height = arg.start_height + arg.m_block_ids.size()-1;
2531 if(context.m_last_response_height > context.m_remote_blockchain_height)
2532 {
2533 LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with m_total_height=" << arg.total_height
2534 << ", m_start_height=" << arg.start_height
2535 << ", m_block_ids.size()=" << arg.m_block_ids.size());
2536 drop_connection(context, false, false);
2537 return 1;
2538 }
2539
2540 uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
2541 if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
2542 {
2543 LOG_ERROR_CCONTEXT("Most blocks are invalid, dropping connection");
2544 drop_connection(context, true, false);
2545 return 1;
2546 }
2547
2548 context.m_expected_heights_start = arg.start_height;
2549
2550 context.m_expected_heights.clear();
2551 context.m_expected_heights.reserve(arg.m_block_ids.size());
2552 context.m_needed_objects.clear();
2553 context.m_needed_objects.reserve(arg.m_block_ids.size());
2554 uint64_t added = 0;
2555 std::unordered_set<crypto::hash> blocks_found;
2556 bool expect_unknown = false;
2557 for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
2558 {
2559 if (!blocks_found.insert(arg.m_block_ids[i]).second)
2560 {
2561 LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
2562 drop_connection_with_score(context, 5, false);
2563 return 1;
2564 }
2565 int where;
2566 const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
2567 if (i == 0)
2568 {
2569 // our outgoing chainlist only has proven blocks (i.e. downloaded)
2570 if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
2571 {
2572 LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
2573 drop_connection_with_score(context, 5, false);
2574 return 1;
2575 }
2576 if (!have_block)
2577 expect_unknown = true;
2578 }
2579 if (0 < i)
2580 {
2581 // after the first, blocks may be known or unknown, but if they are known,
2582 // they should be at the same height if on the main chain
2583 if (have_block)
2584 {
2585 switch (where)
2586 {
2587 default:
2588 case HAVE_BLOCK_INVALID:
2589 LOG_ERROR_CCONTEXT("Block is invalid or known without known type, dropping connection");
2590 drop_connection(context, true, false);
2591 return 1;
2593 if (expect_unknown)
2594 {
2595 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2596 drop_connection_with_score(context, 5, false);
2597 return 1;
2598 }
2599 if (m_core.get_block_id_by_height(arg.start_height + i) != arg.m_block_ids[i])
2600 {
2601 LOG_ERROR_CCONTEXT("Block is on the main chain, but not at the expected height, dropping connection");
2602 drop_connection_with_score(context, 5, false);
2603 return 1;
2604 }
2605 break;
2607 if (expect_unknown)
2608 {
2609 LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
2610 drop_connection_with_score(context, 5, false);
2611 return 1;
2612 }
2613 break;
2614 }
2615 }
2616 else
2617 expect_unknown = true;
2618 }
2619 const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
2620 context.m_expected_heights.push_back(arg.m_block_ids[i]);
2621 context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
2622 if (++added == n_use_blocks)
2623 break;
2624 }
2625 context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
2626
2627 if (!request_missing_objects(context, false))
2628 {
2629 LOG_ERROR_CCONTEXT("Failed to request missing objects, dropping connection");
2630 drop_connection(context, false, false);
2631 return 1;
2632 }
2633
2634 if (arg.total_height > m_core.get_target_blockchain_height())
2635 m_core.set_target_blockchain_height(arg.total_height);
2636
2637 context.m_num_requested = 0;
2638 return 1;
2639 }
2640 //------------------------------------------------------------------------------------------------------------------------
2641 template<class t_core>
2643 {
2644 // sort peers between fluffy ones and others
2645 std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> fluffyConnections;
2646 m_p2p->for_each_connection([this, &exclude_context, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
2647 {
2648 // peer_id also filters out connections before handshake
2649 if (peer_id && exclude_context.m_connection_id != context.m_connection_id && context.m_remote_address.get_zone() == epee::net_utils::zone::public_)
2650 {
2651 LOG_DEBUG_CC(context, "RELAYING FLUFFY BLOCK TO PEER");
2652 fluffyConnections.push_back({context.m_remote_address.get_zone(), context.m_connection_id});
2653 }
2654 return true;
2655 });
2656
2657 // send fluffy ones first, we want to encourage people to run that
2658 if (!fluffyConnections.empty())
2659 {
2660 epee::levin::message_writer fluffyBlob{32 * 1024};
2662 m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, std::move(fluffyBlob), std::move(fluffyConnections));
2663 }
2664
2665 return true;
2666 }
2667 //------------------------------------------------------------------------------------------------------------------------
2668 template<class t_core>
2670 {
2671 /* Push all outgoing transactions to this function. The behavior needs to
2672 identify how the transaction is going to be relayed, and then update the
2673 local mempool before doing the relay. The code was already updating the
2674 DB twice on received transactions - it is difficult to workaround this
2675 due to the internal design. */
2676 return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid;
2677 }
2678 //------------------------------------------------------------------------------------------------------------------------
2679 template<class t_core>
2681 {
2683 if (!m_core.get_pool_transaction_hashes(r.hashes, false))
2684 {
2685 MERROR("Failed to get txpool hashes");
2686 return false;
2687 }
2688 MLOG_P2P_MESSAGE("-->>NOTIFY_GET_TXPOOL_COMPLEMENT: hashes.size()=" << r.hashes.size() );
2690 MLOG_PEER_STATE("requesting txpool complement");
2691 return true;
2692 }
2693 //------------------------------------------------------------------------------------------------------------------------
2694 template<class t_core>
2696 {
2697 if (score <= 0)
2698 {
2699 MERROR("Negative score hit");
2700 return;
2701 }
2702 context.m_score -= score;
2703 if (context.m_score <= DROP_PEERS_ON_SCORE)
2704 drop_connection_with_score(context, 5, false);
2705 }
2706 //------------------------------------------------------------------------------------------------------------------------
2707 template<class t_core>
2709 {
2710 std::stringstream ss;
2711 const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
2712 m_p2p->for_each_connection([&](const connection_context &ctx, nodetool::peerid_type peer_id, uint32_t support_flags) {
2714 char state_char = cryptonote::get_protocol_state_char(ctx.m_state);
2715 ss << stripe + state_char;
2716 if (ctx.m_last_request_time != boost::date_time::not_a_date_time)
2717 ss << (((now - ctx.m_last_request_time).total_microseconds() > IDLE_PEER_KICK_TIME) ? "!" : "?");
2718 ss << + " ";
2719 return true;
2720 });
2721 return ss.str();
2722 }
2723 //------------------------------------------------------------------------------------------------------------------------
2724 template<class t_core>
2726 {
2727 const uint64_t want_height_from_blockchain = m_core.get_current_blockchain_height();
2728 const uint64_t want_height_from_block_queue = m_block_queue.get_next_needed_height(want_height_from_blockchain);
2729 const uint64_t want_height = std::max(want_height_from_blockchain, want_height_from_block_queue);
2730 uint64_t blockchain_height = m_core.get_target_blockchain_height();
2731 // 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
2732 if (blockchain_height == 0)
2733 blockchain_height = CRYPTONOTE_MAX_BLOCK_NUMBER;
2734 const uint32_t next_pruning_stripe = tools::get_pruning_stripe(want_height, blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
2735 if (next_pruning_stripe == 0)
2736 return std::make_pair(0, 0);
2737 // if we already have a few peers on this stripe, but none on next one, try next one
2738 unsigned int n_next = 0, n_subsequent = 0, n_others = 0;
2739 const uint32_t subsequent_pruning_stripe = 1 + next_pruning_stripe % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES);
2740 m_p2p->for_each_connection([&](const connection_context &context, nodetool::peerid_type peer_id, uint32_t support_flags) {
2742 {
2743 if (context.m_pruning_seed == 0 || tools::get_pruning_stripe(context.m_pruning_seed) == next_pruning_stripe)
2744 ++n_next;
2745 else if (tools::get_pruning_stripe(context.m_pruning_seed) == subsequent_pruning_stripe)
2746 ++n_subsequent;
2747 else
2748 ++n_others;
2749 }
2750 return true;
2751 });
2752 // TODO: investigate tallying by zone and comparing to max out peers by zone
2753 const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_);
2754 const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0);
2755 const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe;
2756 MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" <<
2757 want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " <<
2758 next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " <<
2759 subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" <<
2760 (ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) <<
2761 "), current peers " << po);
2762 return std::make_pair(next_pruning_stripe, ret_stripe);
2763 }
2764 //------------------------------------------------------------------------------------------------------------------------
2765 template<class t_core>
2767 {
2768 const uint64_t target = m_core.get_target_blockchain_height();
2769 const uint64_t height = m_core.get_current_blockchain_height();
2770 if (target && target <= height)
2771 return false;
2772 size_t n_out_peers = 0;
2773 m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{
2774 if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone)
2775 ++n_out_peers;
2776 return true;
2777 });
2778 if (n_out_peers >= get_max_out_peers(zone))
2779 return false;
2780 return true;
2781 }
2782 //------------------------------------------------------------------------------------------------------------------------
2783 template<class t_core>
2785 {
2786 const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
2787 return !sync.owns_lock();
2788 }
2789 //------------------------------------------------------------------------------------------------------------------------
2790 template<class t_core>
2792 {
2793 LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
2794 epee::string_tools::to_string_hex(context.m_pruning_seed) <<
2795 "), score " << score << ", flush_all_spans " << flush_all_spans);
2796
2797 if (score > 0)
2798 m_p2p->add_host_fail(context.m_remote_address, score);
2799
2800 m_block_queue.flush_spans(context.m_connection_id, flush_all_spans);
2801
2802 m_p2p->drop_connection(context);
2803 }
2804 //------------------------------------------------------------------------------------------------------------------------
2805 template<class t_core>
2807 {
2808 return drop_connection_with_score(context, add_fail ? 1 : 0, flush_all_spans);
2809 }
2810 //------------------------------------------------------------------------------------------------------------------------
2811 template<class t_core>
2813 {
2814 m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2815 // This _could be_ outside of strand, so careful on actions
2816 drop_connection(context, true, false);
2817 return true;
2818 });
2819 }
2820 //------------------------------------------------------------------------------------------------------------------------
2821 template<class t_core>
2823 {
2824 MWARNING("dropping connections to " << address.str());
2825
2826 m_p2p->add_host_fail(address, 5);
2827
2828 std::vector<boost::uuids::uuid> drop;
2829 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2830 if (address.is_same_host(cntxt.m_remote_address))
2831 drop.push_back(cntxt.m_connection_id);
2832 return true;
2833 });
2834 for (const boost::uuids::uuid &id: drop)
2835 {
2836 m_block_queue.flush_spans(id, true);
2837 m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
2838 // This _could be_ outside of strand, so careful on actions
2839 drop_connection(context, true, false);
2840 return true;
2841 });
2842 }
2843 }
2844 //------------------------------------------------------------------------------------------------------------------------
2845 template<class t_core>
2847 {
2848 uint64_t target = 0;
2849 m_p2p->for_each_connection([&](const connection_context& cntxt, nodetool::peerid_type peer_id, uint32_t support_flags) {
2850 if (cntxt.m_state >= cryptonote_connection_context::state_synchronizing && cntxt.m_connection_id != context.m_connection_id)
2851 target = std::max(target, cntxt.m_remote_blockchain_height);
2852 return true;
2853 });
2854 const uint64_t previous_target = m_core.get_target_blockchain_height();
2855 if (target < previous_target)
2856 {
2857 MINFO("Target height decreasing from " << previous_target << " to " << target);
2858 m_core.set_target_blockchain_height(target);
2859 if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
2860 {
2861 MCWARNING("global", "monerod is now disconnected from the network");
2863 }
2864 }
2865
2866 m_block_queue.flush_spans(context.m_connection_id, false);
2867 MLOG_PEER_STATE("closed");
2868 }
2869
2870 //------------------------------------------------------------------------------------------------------------------------
2871 template<class t_core>
2873 {
2874 m_stopping = true;
2875 m_core.stop();
2876 }
2877} // namespace
2878
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:2806
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:2725
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:2007
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:2695
boost::mutex m_buffer_mutex
Definition cryptonote_protocol_handler.h:203
std::string get_peers_overview() const
Definition cryptonote_protocol_handler.inl:2708
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:1654
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:1983
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:2669
bool request_txpool_complement(cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:2680
void drop_connections(const epee::net_utils::network_address address)
Definition cryptonote_protocol_handler.inl:2822
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:1685
bool update_sync_search()
Definition cryptonote_protocol_handler.inl:1711
int handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request &arg, cryptonote_connection_context &context)
Definition cryptonote_protocol_handler.inl:1784
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:2474
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:1815
t_core & m_core
Definition cryptonote_protocol_handler.h:171
size_t get_synchronizing_connections_count()
Definition cryptonote_protocol_handler.inl:2462
size_t skip_unneeded_hashes(cryptonote_connection_context &context, bool check_block_queue) const
Definition cryptonote_protocol_handler.inl:1962
virtual bool relay_block(NOTIFY_NEW_FLUFFY_BLOCK::request &arg, cryptonote_connection_context &exclude_context)
Definition cryptonote_protocol_handler.inl:2642
bool is_busy_syncing()
Definition cryptonote_protocol_handler.inl:2784
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:1676
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:1768
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:2390
cryptonote_connection_context connection_context
Definition cryptonote_protocol_handler.h:82
void stop()
Definition cryptonote_protocol_handler.inl:2872
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:2791
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:2766
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:2846
bool should_drop_connection(cryptonote_connection_context &context, uint32_t next_stripe)
Definition cryptonote_protocol_handler.inl:1900
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 int version
Definition mdb_load.c:29
const char * text
Definition minihttptestserver.c:269
uint32_t address
Definition getifaddr.c:269
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:126
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
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:1507
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:1579
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:1116
crypto::hash get_pruned_transaction_hash(const transaction &t, const crypto::hash &pruned_data_hash)
Definition cryptonote_format_utils.cpp:1329
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:121
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:1553
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
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