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