@@ -300,9 +300,12 @@ class NetinfoRequestHandler : public BaseRequestHandler
300
300
{
301
301
private:
302
302
static constexpr int8_t UNKNOWN_NETWORK{-1 };
303
- static constexpr uint8_t m_networks_size{3 };
304
- const std::array<std::string, m_networks_size> m_networks{{" ipv4" , " ipv6" , " onion" }};
305
- std::array<std::array<uint16_t , m_networks_size + 2 >, 3 > m_counts{{{}}}; // !< Peer counts by (in/out/total, networks/total/block-relay)
303
+ static constexpr int8_t NET_I2P{3 }; // pos of "i2p" in m_networks
304
+ static constexpr uint8_t m_networks_size{4 };
305
+ const std::array<std::string, m_networks_size> m_networks{{" ipv4" , " ipv6" , " onion" , " i2p" }};
306
+ std::array<std::array<uint16_t , m_networks_size + 1 >, 3 > m_counts{{{}}}; // !< Peer counts by (in/out/total, networks/total)
307
+ uint8_t m_block_relay_peers_count{0 };
308
+ uint8_t m_manual_peers_count{0 };
306
309
int8_t NetworkStringToId (const std::string& str) const
307
310
{
308
311
for (uint8_t i = 0 ; i < m_networks_size; ++i) {
@@ -316,12 +319,14 @@ class NetinfoRequestHandler : public BaseRequestHandler
316
319
bool IsAddressSelected () const { return m_details_level == 2 || m_details_level == 4 ; }
317
320
bool IsVersionSelected () const { return m_details_level == 3 || m_details_level == 4 ; }
318
321
bool m_is_asmap_on{false };
322
+ bool m_is_i2p_on{false };
319
323
size_t m_max_addr_length{0 };
320
- size_t m_max_age_length{4 };
324
+ size_t m_max_age_length{3 };
321
325
size_t m_max_id_length{2 };
322
326
struct Peer {
323
327
std::string addr;
324
328
std::string sub_version;
329
+ std::string conn_type;
325
330
std::string network;
326
331
std::string age;
327
332
double min_ping;
@@ -333,6 +338,8 @@ class NetinfoRequestHandler : public BaseRequestHandler
333
338
int id;
334
339
int mapped_as;
335
340
int version;
341
+ bool is_bip152_hb_from;
342
+ bool is_bip152_hb_to;
336
343
bool is_block_relay;
337
344
bool is_outbound;
338
345
bool operator <(const Peer& rhs) const { return std::tie (is_outbound, min_ping) < std::tie (rhs.is_outbound , rhs.min_ping ); }
@@ -351,6 +358,14 @@ class NetinfoRequestHandler : public BaseRequestHandler
351
358
const double milliseconds{round (1000 * seconds)};
352
359
return milliseconds > 999999 ? " -" : ToString (milliseconds);
353
360
}
361
+ std::string ConnectionTypeForNetinfo (const std::string& conn_type) const
362
+ {
363
+ if (conn_type == " outbound-full-relay" ) return " full" ;
364
+ if (conn_type == " block-relay-only" ) return " block" ;
365
+ if (conn_type == " manual" || conn_type == " feeler" ) return conn_type;
366
+ if (conn_type == " addr-fetch" ) return " addr" ;
367
+ return " " ;
368
+ }
354
369
const UniValue NetinfoHelp ()
355
370
{
356
371
return std::string{
@@ -379,21 +394,27 @@ class NetinfoRequestHandler : public BaseRequestHandler
379
394
" type Type of peer connection\n "
380
395
" \" full\" - full relay, the default\n "
381
396
" \" block\" - block relay; like full relay but does not relay transactions or addresses\n "
397
+ " \" manual\" - peer we manually added using RPC addnode or the -addnode/-connect config options\n "
398
+ " \" feeler\" - short-lived connection for testing addresses\n "
399
+ " \" addr\" - address fetch; short-lived connection for requesting addresses\n "
382
400
" net Network the peer connected through (\" ipv4\" , \" ipv6\" , \" onion\" , \" i2p\" , or \" cjdns\" )\n "
383
401
" mping Minimum observed ping time, in milliseconds (ms)\n "
384
402
" ping Last observed ping time, in milliseconds (ms)\n "
385
403
" send Time since last message sent to the peer, in seconds\n "
386
404
" recv Time since last message received from the peer, in seconds\n "
387
405
" txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n "
388
406
" blk Time since last novel block passing initial validity checks received from the peer, in minutes\n "
407
+ " hb High-bandwidth BIP152 compact block relay\n "
408
+ " \" .\" (to) - we selected the peer as a high-bandwidth peer\n "
409
+ " \" *\" (from) - the peer selected us as a high-bandwidth peer\n "
389
410
" age Duration of connection to the peer, in minutes\n "
390
411
" asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying\n "
391
412
" peer selection (only displayed if the -asmap config option is set)\n "
392
413
" id Peer index, in increasing order of peer connections since node startup\n "
393
414
" address IP address and port of the peer\n "
394
415
" version Peer version and subversion concatenated, e.g. \" 70016/Satoshi:21.0.0/\"\n\n "
395
416
" * The connection counts table displays the number of peers by direction, network, and the totals\n "
396
- " for each, as well as a column for block relay peers.\n\n "
417
+ " for each, as well as two special outbound columns for block relay peers and manual peers.\n\n "
397
418
" * The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n "
398
419
" Examples:\n\n "
399
420
" Connection counts and local addresses only\n "
@@ -450,16 +471,16 @@ class NetinfoRequestHandler : public BaseRequestHandler
450
471
const std::string network{peer[" network" ].get_str ()};
451
472
const int8_t network_id{NetworkStringToId (network)};
452
473
if (network_id == UNKNOWN_NETWORK) continue ;
474
+ m_is_i2p_on |= (network_id == NET_I2P);
453
475
const bool is_outbound{!peer[" inbound" ].get_bool ()};
454
476
const bool is_block_relay{!peer[" relaytxes" ].get_bool ()};
477
+ const std::string conn_type{peer[" connection_type" ].get_str ()};
455
478
++m_counts.at (is_outbound).at (network_id); // in/out by network
456
479
++m_counts.at (is_outbound).at (m_networks_size); // in/out overall
457
480
++m_counts.at (2 ).at (network_id); // total by network
458
481
++m_counts.at (2 ).at (m_networks_size); // total overall
459
- if (is_block_relay) {
460
- ++m_counts.at (is_outbound).at (m_networks_size + 1 ); // in/out block-relay
461
- ++m_counts.at (2 ).at (m_networks_size + 1 ); // total block-relay
462
- }
482
+ if (conn_type == " block-relay-only" ) ++m_block_relay_peers_count;
483
+ if (conn_type == " manual" ) ++m_manual_peers_count;
463
484
if (DetailsRequested ()) {
464
485
// Push data for this peer to the peers vector.
465
486
const int peer_id{peer[" id" ].get_int ()};
@@ -475,7 +496,9 @@ class NetinfoRequestHandler : public BaseRequestHandler
475
496
const std::string addr{peer[" addr" ].get_str ()};
476
497
const std::string age{conn_time == 0 ? " " : ToString ((m_time_now - conn_time) / 60 )};
477
498
const std::string sub_version{peer[" subver" ].get_str ()};
478
- m_peers.push_back ({addr, sub_version, network, age, min_ping, ping, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_block_relay, is_outbound});
499
+ const bool is_bip152_hb_from{peer[" bip152_hb_from" ].get_bool ()};
500
+ const bool is_bip152_hb_to{peer[" bip152_hb_to" ].get_bool ()};
501
+ m_peers.push_back ({addr, sub_version, conn_type, network, age, min_ping, ping, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_bip152_hb_from, is_bip152_hb_to, is_block_relay, is_outbound});
479
502
m_max_addr_length = std::max (addr.length () + 1 , m_max_addr_length);
480
503
m_max_age_length = std::max (age.length (), m_max_age_length);
481
504
m_max_id_length = std::max (ToString (peer_id).length (), m_max_id_length);
@@ -489,22 +512,23 @@ class NetinfoRequestHandler : public BaseRequestHandler
489
512
// Report detailed peer connections list sorted by direction and minimum ping time.
490
513
if (DetailsRequested () && !m_peers.empty ()) {
491
514
std::sort (m_peers.begin (), m_peers.end ());
492
- result += strprintf (" <-> relay net mping ping send recv txn blk %*s " , m_max_age_length, " age" );
515
+ result += strprintf (" <-> type net mping ping send recv txn blk hb %*s " , m_max_age_length, " age" );
493
516
if (m_is_asmap_on) result += " asmap " ;
494
517
result += strprintf (" %*s %-*s%s\n " , m_max_id_length, " id" , IsAddressSelected () ? m_max_addr_length : 0 , IsAddressSelected () ? " address" : " " , IsVersionSelected () ? " version" : " " );
495
518
for (const Peer& peer : m_peers) {
496
519
std::string version{ToString (peer.version ) + peer.sub_version };
497
520
result += strprintf (
498
- " %3s %5s %5s%7s%7s%5s%5s%5s%5s %*s%*i %*s %-*s%s\n " ,
521
+ " %3s %6s %5s%7s%7s%5s%5s%5s%5s %2s %*s%*i %*s %-*s%s\n " ,
499
522
peer.is_outbound ? " out" : " in" ,
500
- peer.is_block_relay ? " block " : " full " ,
523
+ ConnectionTypeForNetinfo ( peer.conn_type ) ,
501
524
peer.network ,
502
525
PingTimeToString (peer.min_ping ),
503
526
PingTimeToString (peer.ping ),
504
527
peer.last_send == 0 ? " " : ToString (m_time_now - peer.last_send ),
505
528
peer.last_recv == 0 ? " " : ToString (m_time_now - peer.last_recv ),
506
529
peer.last_trxn == 0 ? " " : ToString ((m_time_now - peer.last_trxn ) / 60 ),
507
530
peer.last_blck == 0 ? " " : ToString ((m_time_now - peer.last_blck ) / 60 ),
531
+ strprintf (" %s%s" , peer.is_bip152_hb_to ? " ." : " " , peer.is_bip152_hb_from ? " *" : " " ),
508
532
m_max_age_length, // variable spacing
509
533
peer.age ,
510
534
m_is_asmap_on ? 7 : 0 , // variable spacing
@@ -515,18 +539,27 @@ class NetinfoRequestHandler : public BaseRequestHandler
515
539
IsAddressSelected () ? peer.addr : " " ,
516
540
IsVersionSelected () && version != " 0" ? version : " " );
517
541
}
518
- result += strprintf (" ms ms sec sec min min %*s\n\n " , m_max_age_length, " min" );
542
+ result += strprintf (" ms ms sec sec min min %*s\n\n " , m_max_age_length, " min" );
519
543
}
520
544
521
545
// Report peer connection totals by type.
522
- result += " ipv4 ipv6 onion total block-relay\n " ;
546
+ result += " ipv4 ipv6 onion" ;
547
+ if (m_is_i2p_on) result += " i2p" ;
548
+ result += " total block" ;
549
+ if (m_manual_peers_count) result += " manual" ;
523
550
const std::array<std::string, 3 > rows{{" in" , " out" , " total" }};
524
- for (uint8_t i = 0 ; i < m_networks_size; ++i) {
525
- result += strprintf (" %-5s %5i %5i %5i %5i %5i\n " , rows.at (i), m_counts.at (i).at (0 ), m_counts.at (i).at (1 ), m_counts.at (i).at (2 ), m_counts.at (i).at (m_networks_size), m_counts.at (i).at (m_networks_size + 1 ));
551
+ for (uint8_t i = 0 ; i < 3 ; ++i) {
552
+ result += strprintf (" \n %-5s %5i %5i %5i" , rows.at (i), m_counts.at (i).at (0 ), m_counts.at (i).at (1 ), m_counts.at (i).at (2 )); // ipv4/ipv6/onion peers counts
553
+ if (m_is_i2p_on) result += strprintf (" %5i" , m_counts.at (i).at (3 )); // i2p peers count
554
+ result += strprintf (" %5i" , m_counts.at (i).at (m_networks_size)); // total peers count
555
+ if (i == 1 ) { // the outbound row has two extra columns for block relay and manual peer counts
556
+ result += strprintf (" %5i" , m_block_relay_peers_count);
557
+ if (m_manual_peers_count) result += strprintf (" %5i" , m_manual_peers_count);
558
+ }
526
559
}
527
560
528
561
// Report local addresses, ports, and scores.
529
- result += " \n Local addresses" ;
562
+ result += " \n\ n Local addresses" ;
530
563
const std::vector<UniValue>& local_addrs{networkinfo[" localaddresses" ].getValues ()};
531
564
if (local_addrs.empty ()) {
532
565
result += " : n/a\n " ;
0 commit comments