rippled
PeerImp.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/consensus/RCLValidations.h>
21 #include <ripple/app/ledger/InboundLedgers.h>
22 #include <ripple/app/ledger/InboundTransactions.h>
23 #include <ripple/app/ledger/LedgerMaster.h>
24 #include <ripple/app/ledger/TransactionMaster.h>
25 #include <ripple/app/misc/HashRouter.h>
26 #include <ripple/app/misc/LoadFeeTrack.h>
27 #include <ripple/app/misc/NetworkOPs.h>
28 #include <ripple/app/misc/Transaction.h>
29 #include <ripple/app/misc/ValidatorList.h>
30 #include <ripple/app/tx/apply.h>
31 #include <ripple/basics/SubmitSync.h>
32 #include <ripple/basics/UptimeClock.h>
33 #include <ripple/basics/base64.h>
34 #include <ripple/basics/random.h>
35 #include <ripple/basics/safe_cast.h>
36 #include <ripple/beast/core/LexicalCast.h>
37 #include <ripple/beast/core/SemanticVersion.h>
38 #include <ripple/nodestore/DatabaseShard.h>
39 #include <ripple/overlay/Cluster.h>
40 #include <ripple/overlay/impl/PeerImp.h>
41 #include <ripple/overlay/impl/Tuning.h>
42 #include <ripple/overlay/predicates.h>
43 #include <ripple/protocol/Protocol.h>
44 #include <ripple/protocol/digest.h>
45 
46 #include <boost/algorithm/string/predicate.hpp>
47 #include <boost/beast/core/ostream.hpp>
48 
49 #include <algorithm>
50 #include <chrono>
51 #include <memory>
52 #include <mutex>
53 #include <numeric>
54 #include <sstream>
55 
56 using namespace std::chrono_literals;
57 
58 namespace ripple {
59 
60 namespace {
62 std::chrono::milliseconds constexpr peerHighLatency{300};
63 
65 std::chrono::seconds constexpr peerTimerInterval{60};
66 } // namespace
67 
69 closeReasonToString(protocol::TMCloseReason reason)
70 {
71  switch (reason)
72  {
73  case protocol::TMCloseReason::crCHARGE_RESOURCES:
74  return "Charge: Resources";
75  case protocol::TMCloseReason::crMALFORMED_HANDSHAKE1:
76  return "Malformed handshake data (1)";
77  case protocol::TMCloseReason::crMALFORMED_HANDSHAKE2:
78  return "Malformed handshake data (2)";
79  case protocol::TMCloseReason::crMALFORMED_HANDSHAKE3:
80  return "Malformed handshake data (3)";
81  case protocol::TMCloseReason::crLARGE_SENDQUEUE:
82  return "Large send queue";
83  case protocol::TMCloseReason::crNOT_USEFUL:
84  return "Not useful";
85  case protocol::TMCloseReason::crPING_TIMEOUT:
86  return "Ping timeout";
87  default:
88  return "Unknown reason";
89  }
90 }
91 
92 PeerImp::PeerImp(
93  Application& app,
94  id_t id,
96  http_request_type&& request,
97  PublicKey const& publicKey,
99  Resource::Consumer consumer,
100  std::unique_ptr<stream_type>&& stream_ptr,
101  OverlayImpl& overlay)
102  : Child(overlay)
103  , app_(app)
104  , id_(id)
105  , sink_(app_.journal("Peer"), makePrefix(id))
106  , p_sink_(app_.journal("Protocol"), makePrefix(id))
107  , journal_(sink_)
108  , p_journal_(p_sink_)
109  , stream_ptr_(std::move(stream_ptr))
110  , socket_(stream_ptr_->next_layer().socket())
111  , stream_(*stream_ptr_)
112  , strand_(socket_.get_executor())
113  , timer_(waitable_timer{socket_.get_executor()})
114  , remote_address_(slot->remote_endpoint())
115  , overlay_(overlay)
116  , inbound_(true)
117  , protocol_(protocol)
118  , tracking_(Tracking::unknown)
119  , trackingTime_(clock_type::now())
120  , publicKey_(publicKey)
121  , lastPingTime_(clock_type::now())
122  , creationTime_(clock_type::now())
123  , squelch_(app_.journal("Squelch"))
124  , usage_(consumer)
125  , fee_(Resource::feeLightPeer)
126  , slot_(slot)
127  , request_(std::move(request))
128  , headers_(request_)
129  , compressionEnabled_(
131  headers_,
133  "lz4",
134  app_.config().COMPRESSION)
135  ? Compressed::On
136  : Compressed::Off)
137  , txReduceRelayEnabled_(peerFeatureEnabled(
138  headers_,
139  FEATURE_TXRR,
140  app_.config().TX_REDUCE_RELAY_ENABLE))
141  , vpReduceRelayEnabled_(peerFeatureEnabled(
142  headers_,
143  FEATURE_VPRR,
144  app_.config().VP_REDUCE_RELAY_ENABLE))
145  , ledgerReplayEnabled_(peerFeatureEnabled(
146  headers_,
148  app_.config().LEDGER_REPLAY))
149  , ledgerReplayMsgHandler_(app, app.getLedgerReplayer())
150 {
151  JLOG(journal_.info()) << "compression enabled "
152  << (compressionEnabled_ == Compressed::On)
153  << " vp reduce-relay enabled "
154  << vpReduceRelayEnabled_
155  << " tx reduce-relay enabled "
156  << txReduceRelayEnabled_ << " on " << remote_address_
157  << " " << id_;
158  if (auto member = app_.cluster().member(publicKey_))
159  {
160  name_ = *member;
161  JLOG(journal_.info()) << "Cluster name: " << *member;
162  }
163 }
164 
166 {
167  const bool inCluster{cluster()};
168 
173 
174  if (inCluster)
175  {
176  JLOG(journal_.warn()) << name() << " left cluster";
177  }
178 }
179 
180 // Helper function to check for valid uint256 values in protobuf buffers
181 static bool
183 {
184  return pBuffStr.size() == uint256::size();
185 }
186 
187 void
189 {
190  if (!strand_.running_in_this_thread())
191  return post(strand_, std::bind(&PeerImp::run, shared_from_this()));
192 
193  auto parseLedgerHash =
194  [](std::string const& value) -> std::optional<uint256> {
195  if (uint256 ret; ret.parseHex(value))
196  return ret;
197 
198  if (auto const s = base64_decode(value); s.size() == uint256::size())
199  return uint256{s};
200 
201  return std::nullopt;
202  };
203 
204  std::optional<uint256> closed;
205  std::optional<uint256> previous;
206 
207  if (auto const iter = headers_.find("Closed-Ledger");
208  iter != headers_.end())
209  {
210  closed = parseLedgerHash(iter->value());
211 
212  if (!closed)
213  fail(protocol::TMCloseReason::crMALFORMED_HANDSHAKE1);
214  }
215 
216  if (auto const iter = headers_.find("Previous-Ledger");
217  iter != headers_.end())
218  {
219  previous = parseLedgerHash(iter->value());
220 
221  if (!previous)
222  fail(protocol::TMCloseReason::crMALFORMED_HANDSHAKE2);
223  }
224 
225  if (previous && !closed)
226  fail(protocol::TMCloseReason::crMALFORMED_HANDSHAKE3);
227 
228  {
230  if (closed)
231  closedLedgerHash_ = *closed;
232  if (previous)
233  previousLedgerHash_ = *previous;
234  }
235 
236  doProtocolStart();
237 
238  // Anything else that needs to be done with the connection should be
239  // done in doProtocolStart
240 }
241 
242 void
244 {
245  if (!strand_.running_in_this_thread())
246  return post(strand_, std::bind(&PeerImp::stop, shared_from_this()));
247  if (socket_.is_open())
248  {
249  // The rationale for using different severity levels is that
250  // outbound connections are under our control and may be logged
251  // at a higher level, but inbound connections are more numerous and
252  // uncontrolled so to prevent log flooding the severity is reduced.
253  //
254  if (inbound_)
255  {
256  JLOG(journal_.debug()) << "Stop";
257  }
258  else
259  {
260  JLOG(journal_.info()) << "Stop";
261  }
262  }
263  close();
264 }
265 
266 //------------------------------------------------------------------------------
267 
268 void
270 {
271  if (!strand_.running_in_this_thread())
272  return post(strand_, std::bind(&PeerImp::send, shared_from_this(), m));
273  if (gracefulClose_)
274  return;
275  if (detaching_)
276  return;
277 
278  auto validator = m->getValidatorKey();
279  if (validator && !squelch_.expireSquelch(*validator))
280  return;
281 
283  safe_cast<TrafficCount::category>(m->getCategory()),
284  false,
285  static_cast<int>(m->getBuffer(compressionEnabled_).size()));
286 
287  auto sendq_size = send_queue_.size();
288 
289  if (sendq_size < Tuning::targetSendQueue)
290  {
291  // To detect a peer that does not read from their
292  // side of the connection, we expect a peer to have
293  // a small senq periodically
294  large_sendq_ = 0;
295  }
296  else if (auto sink = journal_.debug();
297  sink && (sendq_size % Tuning::sendQueueLogFreq) == 0)
298  {
299  std::string const n = name();
300  sink << (n.empty() ? remote_address_.to_string() : n)
301  << " sendq: " << sendq_size;
302  }
303 
304  send_queue_.push(m);
305 
306  if (sendq_size != 0)
307  return;
308 
309  boost::asio::async_write(
310  stream_,
311  boost::asio::buffer(
312  send_queue_.front()->getBuffer(compressionEnabled_)),
313  bind_executor(
314  strand_,
315  std::bind(
318  std::placeholders::_1,
319  std::placeholders::_2)));
320 }
321 
322 void
324 {
325  if (!strand_.running_in_this_thread())
326  return post(
328 
329  if (!txQueue_.empty())
330  {
331  protocol::TMHaveTransactions ht;
332  std::for_each(txQueue_.begin(), txQueue_.end(), [&](auto const& hash) {
333  ht.add_hashes(hash.data(), hash.size());
334  });
335  JLOG(p_journal_.trace()) << "sendTxQueue " << txQueue_.size();
336  txQueue_.clear();
337  send(std::make_shared<Message>(ht, protocol::mtHAVE_TRANSACTIONS));
338  }
339 }
340 
341 void
343 {
344  if (!strand_.running_in_this_thread())
345  return post(
347 
349  {
350  JLOG(p_journal_.warn()) << "addTxQueue exceeds the cap";
351  sendTxQueue();
352  }
353 
354  txQueue_.insert(hash);
355  JLOG(p_journal_.trace()) << "addTxQueue " << txQueue_.size();
356 }
357 
358 void
360 {
361  if (!strand_.running_in_this_thread())
362  return post(
363  strand_,
365 
366  auto removed = txQueue_.erase(hash);
367  JLOG(p_journal_.trace()) << "removeTxQueue " << removed;
368 }
369 
370 void
372 {
373  if ((usage_.charge(fee) == Resource::drop) &&
374  usage_.disconnect(p_journal_) && strand_.running_in_this_thread())
375  {
376  // Sever the connection
378  fail(protocol::TMCloseReason::crCHARGE_RESOURCES);
379  }
380 }
381 
382 //------------------------------------------------------------------------------
383 
384 bool
386 {
387  auto const iter = headers_.find("Crawl");
388  if (iter == headers_.end())
389  return false;
390  return boost::iequals(iter->value(), "public");
391 }
392 
393 bool
395 {
396  return static_cast<bool>(app_.cluster().member(publicKey_));
397 }
398 
401 {
402  if (inbound_)
403  return headers_["User-Agent"];
404  return headers_["Server"];
405 }
406 
409 {
411 
412  ret[jss::public_key] = toBase58(TokenType::NodePublic, publicKey_);
413  ret[jss::address] = remote_address_.to_string();
414 
415  if (inbound_)
416  ret[jss::inbound] = true;
417 
418  if (cluster())
419  {
420  ret[jss::cluster] = true;
421 
422  if (auto const n = name(); !n.empty())
423  // Could move here if Json::Value supported moving from a string
424  ret[jss::name] = n;
425  }
426 
427  if (auto const d = domain(); !d.empty())
428  ret[jss::server_domain] = domain();
429 
430  if (auto const nid = headers_["Network-ID"]; !nid.empty())
431  ret[jss::network_id] = std::string(nid);
432 
433  ret[jss::load] = usage_.balance();
434 
435  if (auto const version = getVersion(); !version.empty())
436  ret[jss::version] = version;
437 
438  ret[jss::protocol] = to_string(protocol_);
439 
440  {
442  if (latency_)
443  ret[jss::latency] = static_cast<Json::UInt>(latency_->count());
444  }
445 
446  ret[jss::uptime] = static_cast<Json::UInt>(
447  std::chrono::duration_cast<std::chrono::seconds>(uptime()).count());
448 
449  std::uint32_t minSeq, maxSeq;
450  ledgerRange(minSeq, maxSeq);
451 
452  if ((minSeq != 0) || (maxSeq != 0))
453  ret[jss::complete_ledgers] =
454  std::to_string(minSeq) + " - " + std::to_string(maxSeq);
455 
456  switch (tracking_.load())
457  {
458  case Tracking::diverged:
459  ret[jss::track] = "diverged";
460  break;
461 
462  case Tracking::unknown:
463  ret[jss::track] = "unknown";
464  break;
465 
466  case Tracking::converged:
467  // Nothing to do here
468  break;
469  }
470 
471  uint256 closedLedgerHash;
472  protocol::TMStatusChange last_status;
473  {
475  closedLedgerHash = closedLedgerHash_;
476  last_status = last_status_;
477  }
478 
479  if (closedLedgerHash != beast::zero)
480  ret[jss::ledger] = to_string(closedLedgerHash);
481 
482  if (last_status.has_newstatus())
483  {
484  switch (last_status.newstatus())
485  {
486  case protocol::nsCONNECTING:
487  ret[jss::status] = "connecting";
488  break;
489 
490  case protocol::nsCONNECTED:
491  ret[jss::status] = "connected";
492  break;
493 
494  case protocol::nsMONITORING:
495  ret[jss::status] = "monitoring";
496  break;
497 
498  case protocol::nsVALIDATING:
499  ret[jss::status] = "validating";
500  break;
501 
502  case protocol::nsSHUTTING:
503  ret[jss::status] = "shutting";
504  break;
505 
506  default:
507  JLOG(p_journal_.warn())
508  << "Unknown status: " << last_status.newstatus();
509  }
510  }
511 
512  ret[jss::metrics] = Json::Value(Json::objectValue);
513  ret[jss::metrics][jss::total_bytes_recv] =
514  std::to_string(metrics_.recv.total_bytes());
515  ret[jss::metrics][jss::total_bytes_sent] =
516  std::to_string(metrics_.sent.total_bytes());
517  ret[jss::metrics][jss::avg_bps_recv] =
518  std::to_string(metrics_.recv.average_bytes());
519  ret[jss::metrics][jss::avg_bps_sent] =
520  std::to_string(metrics_.sent.average_bytes());
521 
522  return ret;
523 }
524 
525 bool
527 {
528  switch (f)
529  {
531  return protocol_ >= make_protocol(2, 1);
533  return protocol_ >= make_protocol(2, 2);
535  return ledgerReplayEnabled_;
537  return protocol_ >= make_protocol(2, 3);
538  }
539  return false;
540 }
541 
542 //------------------------------------------------------------------------------
543 
544 bool
545 PeerImp::hasLedger(uint256 const& hash, std::uint32_t seq) const
546 {
547  {
549  if ((seq != 0) && (seq >= minLedger_) && (seq <= maxLedger_) &&
551  return true;
552  if (std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
553  recentLedgers_.end())
554  return true;
555  }
556 
557  if (seq >= app_.getNodeStore().earliestLedgerSeq())
558  {
560  auto const it{shardInfos_.find(publicKey_)};
561  if (it != shardInfos_.end())
562  {
563  auto const shardIndex{app_.getNodeStore().seqToShardIndex(seq)};
564  return boost::icl::contains(it->second.finalized(), shardIndex);
565  }
566  }
567  return false;
568 }
569 
570 void
572 {
574 
575  minSeq = minLedger_;
576  maxSeq = maxLedger_;
577 }
578 
579 bool
580 PeerImp::hasTxSet(uint256 const& hash) const
581 {
583  return std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
584  recentTxSets_.end();
585 }
586 
587 void
589 {
590  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
591  // guarded by recentLock_.
595 }
596 
597 bool
599 {
601  return (tracking_ != Tracking::diverged) && (uMin >= minLedger_) &&
602  (uMax <= maxLedger_);
603 }
604 
605 //------------------------------------------------------------------------------
606 
607 void
609 {
610  assert(strand_.running_in_this_thread());
611  if (socket_.is_open())
612  {
613  detaching_ = true; // DEPRECATED
614  error_code ec;
615  timer_.cancel(ec);
616  socket_.close(ec);
618  if (inbound_)
619  {
620  JLOG(journal_.debug()) << "Closed";
621  }
622  else
623  {
624  JLOG(journal_.info()) << "Closed";
625  }
626  }
627 }
628 
629 void
630 PeerImp::fail(protocol::TMCloseReason reason)
631 {
632  if (!strand_.running_in_this_thread())
633  return post(
634  strand_,
635  std::bind(
636  (void (Peer::*)(protocol::TMCloseReason)) & PeerImp::fail,
638  reason));
640  {
641  std::string const n = name();
642  JLOG(journal_.warn()) << (n.empty() ? remote_address_.to_string() : n)
643  << " failed: " << closeReasonToString(reason);
644  }
645 
646  // erase all outstanding messages except for the one
647  // currently being executed
648  if (send_queue_.size() > 1)
649  {
650  decltype(send_queue_) q({send_queue_.front()});
651  send_queue_.swap(q);
652  }
653 
654  closeOnWriteComplete_ = true;
655  protocol::TMGracefulClose tmGC;
656  tmGC.set_reason(reason);
657  send(std::make_shared<Message>(tmGC, protocol::mtGRACEFUL_CLOSE));
658 }
659 
660 void
662 {
663  assert(strand_.running_in_this_thread());
664  if (socket_.is_open())
665  {
666  JLOG(journal_.warn())
667  << name << " from " << toBase58(TokenType::NodePublic, publicKey_)
668  << " at " << remote_address_.to_string() << ": " << ec.message();
669  }
670  close();
671 }
672 
675 {
677  return shardInfos_;
678 }
679 
680 void
682 {
683  assert(strand_.running_in_this_thread());
684  assert(socket_.is_open());
685  assert(!gracefulClose_);
686  gracefulClose_ = true;
687  if (send_queue_.size() > 0)
688  return;
689  setTimer();
690  stream_.async_shutdown(bind_executor(
691  strand_,
692  std::bind(
693  &PeerImp::onShutdown, shared_from_this(), std::placeholders::_1)));
694 }
695 
696 void
698 {
699  error_code ec;
700  timer_.expires_from_now(peerTimerInterval, ec);
701 
702  if (ec)
703  {
704  JLOG(journal_.error()) << "setTimer: " << ec.message();
705  return;
706  }
707  timer_.async_wait(bind_executor(
708  strand_,
709  std::bind(
710  &PeerImp::onTimer, shared_from_this(), std::placeholders::_1)));
711 }
712 
713 // convenience for ignoring the error code
714 void
716 {
717  error_code ec;
718  timer_.cancel(ec);
719 }
720 
721 //------------------------------------------------------------------------------
722 
725 {
727  ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
728  return ss.str();
729 }
730 
731 void
733 {
734  if (!socket_.is_open())
735  return;
736 
737  if (ec == boost::asio::error::operation_aborted)
738  return;
739 
740  if (ec)
741  {
742  // This should never happen
743  JLOG(journal_.error()) << "onTimer: " << ec.message();
744  return close();
745  }
746 
748  {
749  fail(protocol::TMCloseReason::crLARGE_SENDQUEUE);
750  return;
751  }
752 
753  if (auto const t = tracking_.load(); !inbound_ && t != Tracking::converged)
754  {
755  clock_type::duration duration;
756 
757  {
759  duration = clock_type::now() - trackingTime_;
760  }
761 
762  if ((t == Tracking::diverged &&
763  (duration > app_.config().MAX_DIVERGED_TIME)) ||
764  (t == Tracking::unknown &&
765  (duration > app_.config().MAX_UNKNOWN_TIME)))
766  {
768  fail(protocol::TMCloseReason::crLARGE_SENDQUEUE);
769  return;
770  }
771  }
772 
773  // Already waiting for PONG
774  if (lastPingSeq_)
775  {
776  fail(protocol::TMCloseReason::crPING_TIMEOUT);
777  return;
778  }
779 
781  lastPingSeq_ = rand_int<std::uint32_t>();
782 
783  protocol::TMPing message;
784  message.set_type(protocol::TMPing::ptPING);
785  message.set_seq(*lastPingSeq_);
786 
787  send(std::make_shared<Message>(message, protocol::mtPING));
788 
789  setTimer();
790 }
791 
792 void
794 {
795  cancelTimer();
796  // If we don't get eof then something went wrong
797  if (!ec)
798  {
799  JLOG(journal_.error()) << "onShutdown: expected error condition";
800  return close();
801  }
802  if (ec != boost::asio::error::eof)
803  return fail("onShutdown", ec);
804  close();
805 }
806 
807 //------------------------------------------------------------------------------
808 
811 {
812  std::shared_lock read_lock{nameMutex_};
813  return name_;
814 }
815 
818 {
819  return headers_["Server-Domain"];
820 }
821 
822 //------------------------------------------------------------------------------
823 
824 // Protocol logic
825 
826 void
828 {
830 
831  bool supportedProtocol = supportsFeature(ProtocolFeature::StartProtocol);
832 
833  if (!inbound_)
834  {
835  // Instruct connected inbound peer to start sending
836  // protocol messages
837  if (supportedProtocol)
838  {
839  JLOG(journal_.debug())
840  << "doProtocolStart(): outbound sending mtSTART_PROTOCOL to "
841  << remote_address_;
842  protocol::TMStartProtocol tmPS;
843  tmPS.set_starttime(std::chrono::duration_cast<std::chrono::seconds>(
844  clock_type::now().time_since_epoch())
845  .count());
846  send(std::make_shared<Message>(tmPS, protocol::mtSTART_PROTOCOL));
847  }
848  else
849  {
850  JLOG(journal_.debug()) << "doProtocolStart(): outbound connected "
851  "to an older protocol on "
852  << remote_address_ << " " << protocol_.first
853  << " " << protocol_.second;
854  }
855 
856  if (auto m = overlay_.getManifestsMessage())
857  send(m);
858 
859  // Request shard info from peer
860  protocol::TMGetPeerShardInfoV2 tmGPS;
861  tmGPS.set_relays(0);
862  send(std::make_shared<Message>(
863  tmGPS, protocol::mtGET_PEER_SHARD_INFO_V2));
864  }
865  // Backward compatibility with the older protocols
866  else if (!supportedProtocol)
867  {
868  JLOG(journal_.debug())
869  << "doProtocolStart(): inbound handling of an older protocol on "
870  << remote_address_ << " " << protocol_.first << " "
871  << protocol_.second;
872  onStartProtocol();
873  }
874 
875  setTimer();
876 }
877 
878 // Called repeatedly with protocol message data
879 void
881 {
882  if (!socket_.is_open())
883  return;
884  if (ec == boost::asio::error::operation_aborted)
885  return;
886  if (ec == boost::asio::error::eof)
887  {
888  JLOG(journal_.info()) << "EOF";
889  return gracefulClose();
890  }
891  if (ec)
892  return fail("onReadMessage", ec);
893  if (auto stream = journal_.trace())
894  {
895  if (bytes_transferred > 0)
896  stream << "onReadMessage: " << bytes_transferred << " bytes";
897  else
898  stream << "onReadMessage";
899  }
900 
901  metrics_.recv.add_message(bytes_transferred);
902 
903  read_buffer_.commit(bytes_transferred);
904 
905  auto hint = Tuning::readBufferBytes;
906 
907  while (read_buffer_.size() > 0)
908  {
909  std::size_t bytes_consumed;
910  std::tie(bytes_consumed, ec) =
911  invokeProtocolMessage(read_buffer_.data(), *this, hint);
912  if (ec)
913  return fail("onReadMessage", ec);
914  if (!socket_.is_open())
915  return;
916  if (gracefulClose_)
917  return;
918  if (bytes_consumed == 0)
919  break;
920  read_buffer_.consume(bytes_consumed);
921  }
922 
923  // Timeout on writes only
924  stream_.async_read_some(
926  bind_executor(
927  strand_,
928  std::bind(
931  std::placeholders::_1,
932  std::placeholders::_2)));
933 }
934 
935 void
937 {
938  if (!socket_.is_open())
939  return;
940  if (ec == boost::asio::error::operation_aborted)
941  {
943  close();
944  return;
945  }
946  if (ec)
947  return fail("onWriteMessage", ec);
948  if (auto stream = journal_.trace())
949  {
950  if (bytes_transferred > 0)
951  stream << "onWriteMessage: " << bytes_transferred << " bytes";
952  else
953  stream << "onWriteMessage";
954  }
955 
956  metrics_.sent.add_message(bytes_transferred);
957 
958  assert(!send_queue_.empty());
959  if (send_queue_.front()->getType() == protocol::mtGRACEFUL_CLOSE)
960  {
961  close();
962  return;
963  }
964  send_queue_.pop();
965  if (!send_queue_.empty())
966  {
967  // Timeout on writes only
968  return boost::asio::async_write(
969  stream_,
970  boost::asio::buffer(
971  send_queue_.front()->getBuffer(compressionEnabled_)),
972  bind_executor(
973  strand_,
974  std::bind(
977  std::placeholders::_1,
978  std::placeholders::_2)));
979  }
980 
981  if (gracefulClose_)
982  {
983  return stream_.async_shutdown(bind_executor(
984  strand_,
985  std::bind(
988  std::placeholders::_1)));
989  }
990 }
991 
992 //------------------------------------------------------------------------------
993 //
994 // ProtocolHandler
995 //
996 //------------------------------------------------------------------------------
997 
998 void
1000 {
1001  // TODO
1002 }
1003 
1004 void
1006  std::uint16_t type,
1008  std::size_t size,
1009  std::size_t uncompressed_size,
1010  bool isCompressed)
1011 {
1012  load_event_ =
1015  auto const category = TrafficCount::categorize(*m, type, true);
1016  overlay_.reportTraffic(category, true, static_cast<int>(size));
1017  using namespace protocol;
1018  if ((type == MessageType::mtTRANSACTION ||
1019  type == MessageType::mtHAVE_TRANSACTIONS ||
1020  type == MessageType::mtTRANSACTIONS ||
1021  // GET_OBJECTS
1022  category == TrafficCount::category::get_transactions ||
1023  // GET_LEDGER
1024  category == TrafficCount::category::ld_tsc_get ||
1025  category == TrafficCount::category::ld_tsc_share ||
1026  // LEDGER_DATA
1027  category == TrafficCount::category::gl_tsc_share ||
1028  category == TrafficCount::category::gl_tsc_get) &&
1030  {
1032  static_cast<MessageType>(type), static_cast<std::uint64_t>(size));
1033  }
1034  JLOG(journal_.trace()) << "onMessageBegin: " << type << " " << size << " "
1035  << uncompressed_size << " " << isCompressed;
1036 }
1037 
1038 void
1040  std::uint16_t,
1042 {
1043  load_event_.reset();
1044  charge(fee_);
1045 }
1046 
1047 void
1049 {
1050  auto const s = m->list_size();
1051 
1052  if (s == 0)
1053  {
1055  return;
1056  }
1057 
1058  if (s > 100)
1060 
1062  jtMANIFEST, "receiveManifests", [this, that = shared_from_this(), m]() {
1063  overlay_.onManifests(m, that);
1064  });
1065 }
1066 
1067 void
1069 {
1070  if (m->type() == protocol::TMPing::ptPING)
1071  {
1072  // We have received a ping request, reply with a pong
1074  m->set_type(protocol::TMPing::ptPONG);
1075  send(std::make_shared<Message>(*m, protocol::mtPING));
1076  return;
1077  }
1078 
1079  if (m->type() == protocol::TMPing::ptPONG && m->has_seq())
1080  {
1081  // Only reset the ping sequence if we actually received a
1082  // PONG with the correct cookie. That way, any peers which
1083  // respond with incorrect cookies will eventually time out.
1084  if (m->seq() == lastPingSeq_)
1085  {
1086  lastPingSeq_.reset();
1087 
1088  // Update latency estimate
1089  auto const rtt = std::chrono::round<std::chrono::milliseconds>(
1091 
1093 
1094  if (latency_)
1095  latency_ = (*latency_ * 7 + rtt) / 8;
1096  else
1097  latency_ = rtt;
1098  }
1099 
1100  return;
1101  }
1102 }
1103 
1104 void
1106 {
1107  // VFALCO NOTE I think we should drop the peer immediately
1108  if (!cluster())
1109  {
1111  return;
1112  }
1113 
1114  for (int i = 0; i < m->clusternodes().size(); ++i)
1115  {
1116  protocol::TMClusterNode const& node = m->clusternodes(i);
1117 
1118  std::string name;
1119  if (node.has_nodename())
1120  name = node.nodename();
1121 
1122  auto const publicKey =
1123  parseBase58<PublicKey>(TokenType::NodePublic, node.publickey());
1124 
1125  // NIKB NOTE We should drop the peer immediately if
1126  // they send us a public key we can't parse
1127  if (publicKey)
1128  {
1129  auto const reportTime =
1130  NetClock::time_point{NetClock::duration{node.reporttime()}};
1131 
1132  app_.cluster().update(
1133  *publicKey, name, node.nodeload(), reportTime);
1134  }
1135  }
1136 
1137  int loadSources = m->loadsources().size();
1138  if (loadSources != 0)
1139  {
1140  Resource::Gossip gossip;
1141  gossip.items.reserve(loadSources);
1142  for (int i = 0; i < m->loadsources().size(); ++i)
1143  {
1144  protocol::TMLoadSource const& node = m->loadsources(i);
1146  item.address = beast::IP::Endpoint::from_string(node.name());
1147  item.balance = node.cost();
1148  if (item.address != beast::IP::Endpoint())
1149  gossip.items.push_back(item);
1150  }
1152  }
1153 
1154  // Calculate the cluster fee:
1155  auto const thresh = app_.timeKeeper().now() - 90s;
1156  std::uint32_t clusterFee = 0;
1157 
1159  fees.reserve(app_.cluster().size());
1160 
1161  app_.cluster().for_each([&fees, thresh](ClusterNode const& status) {
1162  if (status.getReportTime() >= thresh)
1163  fees.push_back(status.getLoadFee());
1164  });
1165 
1166  if (!fees.empty())
1167  {
1168  auto const index = fees.size() / 2;
1169  std::nth_element(fees.begin(), fees.begin() + index, fees.end());
1170  clusterFee = fees[index];
1171  }
1172 
1173  app_.getFeeTrack().setClusterFee(clusterFee);
1174 }
1175 
1176 void
1178 {
1179  // DEPRECATED
1180 }
1181 
1182 void
1184 {
1185  // DEPRECATED
1186 }
1187 
1188 void
1190 {
1191  auto badData = [&](std::string msg) {
1193  JLOG(p_journal_.warn()) << msg;
1194  };
1195 
1196  // Verify relays
1197  if (m->relays() > relayLimit)
1198  return badData("Invalid relays");
1199 
1200  // Verify peer chain
1201  // The peer chain should not contain this node's public key
1202  // nor the public key of the sending peer
1203  std::set<PublicKey> pubKeyChain;
1204  pubKeyChain.insert(app_.nodeIdentity().first);
1205  pubKeyChain.insert(publicKey_);
1206 
1207  auto const peerChainSz{m->peerchain_size()};
1208  if (peerChainSz > 0)
1209  {
1210  if (peerChainSz > relayLimit)
1211  return badData("Invalid peer chain size");
1212 
1213  if (peerChainSz + m->relays() > relayLimit)
1214  return badData("Invalid relays and peer chain size");
1215 
1216  for (int i = 0; i < peerChainSz; ++i)
1217  {
1218  auto const slice{makeSlice(m->peerchain(i).publickey())};
1219 
1220  // Verify peer public key
1221  if (!publicKeyType(slice))
1222  return badData("Invalid peer public key");
1223 
1224  // Verify peer public key is unique in the peer chain
1225  if (!pubKeyChain.emplace(slice).second)
1226  return badData("Invalid peer public key");
1227  }
1228  }
1229 
1230  // Reply with shard info this node may have
1231  if (auto shardStore = app_.getShardStore())
1232  {
1233  auto reply{shardStore->getShardInfo()->makeMessage(app_)};
1234  if (peerChainSz > 0)
1235  *(reply.mutable_peerchain()) = m->peerchain();
1236  send(std::make_shared<Message>(reply, protocol::mtPEER_SHARD_INFO_V2));
1237  }
1238 
1239  if (m->relays() == 0)
1240  return;
1241 
1242  // Charge originating peer a fee for requesting relays
1243  if (peerChainSz == 0)
1245 
1246  // Add peer to the peer chain
1247  m->add_peerchain()->set_publickey(publicKey_.data(), publicKey_.size());
1248 
1249  // Relay the request to peers, exclude the peer chain
1250  m->set_relays(m->relays() - 1);
1252  std::make_shared<Message>(*m, protocol::mtGET_PEER_SHARD_INFO_V2),
1253  [&](std::shared_ptr<Peer> const& peer) {
1254  return pubKeyChain.find(peer->getNodePublic()) != pubKeyChain.end();
1255  }));
1256 }
1257 
1258 void
1260 {
1261  // Find the earliest and latest shard indexes
1262  auto const& db{app_.getNodeStore()};
1263  auto const earliestShardIndex{db.earliestShardIndex()};
1264  auto const latestShardIndex{[&]() -> std::optional<std::uint32_t> {
1265  auto const curLedgerSeq{app_.getLedgerMaster().getCurrentLedgerIndex()};
1266  if (curLedgerSeq >= db.earliestLedgerSeq())
1267  return db.seqToShardIndex(curLedgerSeq);
1268  return std::nullopt;
1269  }()};
1270 
1271  auto badData = [&](std::string msg) {
1273  JLOG(p_journal_.warn()) << msg;
1274  };
1275 
1276  // Used to create a digest and verify the message signature
1277  Serializer s;
1279 
1280  // Verify message creation time
1282  {
1283  auto const timestamp{
1284  NetClock::time_point{std::chrono::seconds{m->timestamp()}}};
1285  auto const now{app_.timeKeeper().now()};
1286  if (timestamp > (now + 5s))
1287  return badData("Invalid timestamp");
1288 
1289  // Check if stale
1290  using namespace std::chrono_literals;
1291  if (timestamp < (now - 5min))
1292  return badData("Stale timestamp");
1293 
1294  s.add32(m->timestamp());
1295  shardInfo.setMsgTimestamp(timestamp);
1296  }
1297 
1298  // Verify incomplete shards
1299  auto const numIncomplete{m->incomplete_size()};
1300  if (numIncomplete > 0)
1301  {
1302  if (latestShardIndex && numIncomplete > *latestShardIndex)
1303  return badData("Invalid number of incomplete shards");
1304 
1305  // Verify each incomplete shard
1306  for (int i = 0; i < numIncomplete; ++i)
1307  {
1308  auto const& incomplete{m->incomplete(i)};
1309  auto const shardIndex{incomplete.shardindex()};
1310 
1311  // Verify shard index
1312  if (shardIndex < earliestShardIndex ||
1313  (latestShardIndex && shardIndex > latestShardIndex))
1314  {
1315  return badData("Invalid incomplete shard index");
1316  }
1317  s.add32(shardIndex);
1318 
1319  // Verify state
1320  auto const state{static_cast<ShardState>(incomplete.state())};
1321  switch (state)
1322  {
1323  // Incomplete states
1324  case ShardState::acquire:
1325  case ShardState::complete:
1327  case ShardState::queued:
1328  break;
1329 
1330  // case ShardState::finalized:
1331  default:
1332  return badData("Invalid incomplete shard state");
1333  }
1334  s.add32(incomplete.state());
1335 
1336  // Verify progress
1337  std::uint32_t progress{0};
1338  if (incomplete.has_progress())
1339  {
1340  progress = incomplete.progress();
1341  if (progress < 1 || progress > 100)
1342  return badData("Invalid incomplete shard progress");
1343  s.add32(progress);
1344  }
1345 
1346  // Verify each incomplete shard is unique
1347  if (!shardInfo.update(shardIndex, state, progress))
1348  return badData("Invalid duplicate incomplete shards");
1349  }
1350  }
1351 
1352  // Verify finalized shards
1353  if (m->has_finalized())
1354  {
1355  auto const& str{m->finalized()};
1356  if (str.empty())
1357  return badData("Invalid finalized shards");
1358 
1359  if (!shardInfo.setFinalizedFromString(str))
1360  return badData("Invalid finalized shard indexes");
1361 
1362  auto const& finalized{shardInfo.finalized()};
1363  auto const numFinalized{boost::icl::length(finalized)};
1364  if (numFinalized == 0 ||
1365  boost::icl::first(finalized) < earliestShardIndex ||
1366  (latestShardIndex &&
1367  boost::icl::last(finalized) > latestShardIndex))
1368  {
1369  return badData("Invalid finalized shard indexes");
1370  }
1371 
1372  if (latestShardIndex &&
1373  (numFinalized + numIncomplete) > *latestShardIndex)
1374  {
1375  return badData("Invalid number of finalized and incomplete shards");
1376  }
1377 
1378  s.addRaw(str.data(), str.size());
1379  }
1380 
1381  // Verify public key
1382  auto slice{makeSlice(m->publickey())};
1383  if (!publicKeyType(slice))
1384  return badData("Invalid public key");
1385 
1386  // Verify peer public key isn't this nodes's public key
1387  PublicKey const publicKey(slice);
1388  if (publicKey == app_.nodeIdentity().first)
1389  return badData("Invalid public key");
1390 
1391  // Verify signature
1392  if (!verify(publicKey, s.slice(), makeSlice(m->signature()), false))
1393  return badData("Invalid signature");
1394 
1395  // Forward the message if a peer chain exists
1396  auto const peerChainSz{m->peerchain_size()};
1397  if (peerChainSz > 0)
1398  {
1399  // Verify peer chain
1400  if (peerChainSz > relayLimit)
1401  return badData("Invalid peer chain size");
1402 
1403  // The peer chain should not contain this node's public key
1404  // nor the public key of the sending peer
1405  std::set<PublicKey> pubKeyChain;
1406  pubKeyChain.insert(app_.nodeIdentity().first);
1407  pubKeyChain.insert(publicKey_);
1408 
1409  for (int i = 0; i < peerChainSz; ++i)
1410  {
1411  // Verify peer public key
1412  slice = makeSlice(m->peerchain(i).publickey());
1413  if (!publicKeyType(slice))
1414  return badData("Invalid peer public key");
1415 
1416  // Verify peer public key is unique in the peer chain
1417  if (!pubKeyChain.emplace(slice).second)
1418  return badData("Invalid peer public key");
1419  }
1420 
1421  // If last peer in the chain is connected, relay the message
1422  PublicKey const peerPubKey(
1423  makeSlice(m->peerchain(peerChainSz - 1).publickey()));
1424  if (auto peer = overlay_.findPeerByPublicKey(peerPubKey))
1425  {
1426  m->mutable_peerchain()->RemoveLast();
1427  peer->send(
1428  std::make_shared<Message>(*m, protocol::mtPEER_SHARD_INFO_V2));
1429  JLOG(p_journal_.trace())
1430  << "Relayed TMPeerShardInfoV2 from peer IP "
1431  << remote_address_.address().to_string() << " to peer IP "
1432  << peer->getRemoteAddress().to_string();
1433  }
1434  else
1435  {
1436  // Peer is no longer available so the relay ends
1437  JLOG(p_journal_.info()) << "Unable to relay peer shard info";
1438  }
1439  }
1440 
1441  JLOG(p_journal_.trace())
1442  << "Consumed TMPeerShardInfoV2 originating from public key "
1443  << toBase58(TokenType::NodePublic, publicKey) << " finalized shards["
1444  << ripple::to_string(shardInfo.finalized()) << "] incomplete shards["
1445  << (shardInfo.incomplete().empty() ? "empty"
1446  : shardInfo.incompleteToString())
1447  << "]";
1448 
1449  // Consume the message
1450  {
1452  auto const it{shardInfos_.find(publicKey_)};
1453  if (it == shardInfos_.end())
1454  shardInfos_.emplace(publicKey, std::move(shardInfo));
1455  else if (shardInfo.msgTimestamp() > it->second.msgTimestamp())
1456  it->second = std::move(shardInfo);
1457  }
1458 
1459  // Notify overlay a reply was received from the last peer in this chain
1460  if (peerChainSz == 0)
1462 }
1463 
1464 void
1466 {
1467  // Don't allow endpoints from peers that are not known tracking or are
1468  // not using a version of the message that we support:
1469  if (tracking_.load() != Tracking::converged || m->version() != 2)
1470  return;
1471 
1472  // The number is arbitrary and doesn't have any real significance or
1473  // implication for the protocol.
1474  if (m->endpoints_v2().size() >= 1024)
1475  {
1477  return;
1478  }
1479 
1481  endpoints.reserve(m->endpoints_v2().size());
1482 
1483  for (auto const& tm : m->endpoints_v2())
1484  {
1485  auto result = beast::IP::Endpoint::from_string_checked(tm.endpoint());
1486 
1487  if (!result)
1488  {
1489  JLOG(p_journal_.error()) << "failed to parse incoming endpoint: {"
1490  << tm.endpoint() << "}";
1492  continue;
1493  }
1494 
1495  // If hops == 0, this Endpoint describes the peer we are connected
1496  // to -- in that case, we take the remote address seen on the
1497  // socket and store that in the IP::Endpoint. If this is the first
1498  // time, then we'll verify that their listener can receive incoming
1499  // by performing a connectivity test. if hops > 0, then we just
1500  // take the address/port we were given
1501  if (tm.hops() == 0)
1502  result = remote_address_.at_port(result->port());
1503 
1504  endpoints.emplace_back(*result, tm.hops());
1505  }
1506 
1507  if (!endpoints.empty())
1508  overlay_.peerFinder().on_endpoints(slot_, endpoints);
1509 }
1510 
1511 void
1513 {
1514  handleTransaction(m, true);
1515 }
1516 
1517 void
1520  bool eraseTxQueue)
1521 {
1523  return;
1524 
1526  {
1527  // If we've never been in synch, there's nothing we can do
1528  // with a transaction
1529  JLOG(p_journal_.debug()) << "Ignoring incoming transaction: "
1530  << "Need network ledger";
1531  return;
1532  }
1533 
1534  SerialIter sit(makeSlice(m->rawtransaction()));
1535 
1536  try
1537  {
1538  auto stx = std::make_shared<STTx const>(sit);
1539  uint256 txID = stx->getTransactionID();
1540 
1541  int flags;
1542  constexpr std::chrono::seconds tx_interval = 10s;
1543 
1544  if (!app_.getHashRouter().shouldProcess(txID, id_, flags, tx_interval))
1545  {
1546  // we have seen this transaction recently
1547  if (flags & SF_BAD)
1548  {
1550  JLOG(p_journal_.debug()) << "Ignoring known bad tx " << txID;
1551  }
1552 
1553  // Erase only if the server has seen this tx. If the server has not
1554  // seen this tx then the tx could not has been queued for this peer.
1555  else if (eraseTxQueue && txReduceRelayEnabled())
1556  removeTxQueue(txID);
1557 
1558  return;
1559  }
1560 
1561  JLOG(p_journal_.debug()) << "Got tx " << txID;
1562 
1563  bool checkSignature = true;
1564  if (cluster())
1565  {
1566  if (!m->has_deferred() || !m->deferred())
1567  {
1568  // Skip local checks if a server we trust
1569  // put the transaction in its open ledger
1570  flags |= SF_TRUSTED;
1571  }
1572 
1574  {
1575  // For now, be paranoid and have each validator
1576  // check each transaction, regardless of source
1577  checkSignature = false;
1578  }
1579  }
1580 
1582  {
1583  JLOG(p_journal_.trace())
1584  << "No new transactions until synchronized";
1585  }
1586  else if (
1589  {
1591  JLOG(p_journal_.info()) << "Transaction queue is full";
1592  }
1593  else
1594  {
1596  jtTRANSACTION,
1597  "recvTransaction->checkTransaction",
1599  flags,
1600  checkSignature,
1601  stx]() {
1602  if (auto peer = weak.lock())
1603  peer->checkTransaction(flags, checkSignature, stx);
1604  });
1605  }
1606  }
1607  catch (std::exception const& ex)
1608  {
1609  JLOG(p_journal_.warn())
1610  << "Transaction invalid: " << strHex(m->rawtransaction())
1611  << ". Exception: " << ex.what();
1612  }
1613 }
1614 
1615 void
1617 {
1618  auto badData = [&](std::string const& msg) {
1620  JLOG(p_journal_.warn()) << "TMGetLedger: " << msg;
1621  };
1622  auto const itype{m->itype()};
1623 
1624  // Verify ledger info type
1625  if (itype < protocol::liBASE || itype > protocol::liTS_CANDIDATE)
1626  return badData("Invalid ledger info type");
1627 
1628  auto const ltype = [&m]() -> std::optional<::protocol::TMLedgerType> {
1629  if (m->has_ltype())
1630  return m->ltype();
1631  return std::nullopt;
1632  }();
1633 
1634  if (itype == protocol::liTS_CANDIDATE)
1635  {
1636  if (!m->has_ledgerhash())
1637  return badData("Invalid TX candidate set, missing TX set hash");
1638  }
1639  else if (
1640  !m->has_ledgerhash() && !m->has_ledgerseq() &&
1641  !(ltype && *ltype == protocol::ltCLOSED))
1642  {
1643  return badData("Invalid request");
1644  }
1645 
1646  // Verify ledger type
1647  if (ltype && (*ltype < protocol::ltACCEPTED || *ltype > protocol::ltCLOSED))
1648  return badData("Invalid ledger type");
1649 
1650  // Verify ledger hash
1651  if (m->has_ledgerhash() && !stringIsUint256Sized(m->ledgerhash()))
1652  return badData("Invalid ledger hash");
1653 
1654  // Verify ledger sequence
1655  if (m->has_ledgerseq())
1656  {
1657  auto const ledgerSeq{m->ledgerseq()};
1658  // Verifying the network's earliest ledger only pertains to shards.
1659  if (app_.getShardStore() &&
1660  ledgerSeq < app_.getNodeStore().earliestLedgerSeq())
1661  {
1662  return badData(
1663  "Invalid ledger sequence " + std::to_string(ledgerSeq));
1664  }
1665 
1666  // Check if within a reasonable range
1667  using namespace std::chrono_literals;
1668  if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s &&
1669  ledgerSeq > app_.getLedgerMaster().getValidLedgerIndex() + 10)
1670  {
1671  return badData(
1672  "Invalid ledger sequence " + std::to_string(ledgerSeq));
1673  }
1674  }
1675 
1676  // Verify ledger node IDs
1677  if (itype != protocol::liBASE)
1678  {
1679  if (m->nodeids_size() <= 0)
1680  return badData("Invalid ledger node IDs");
1681 
1682  for (auto const& nodeId : m->nodeids())
1683  {
1684  if (deserializeSHAMapNodeID(nodeId) == std::nullopt)
1685  return badData("Invalid SHAMap node ID");
1686  }
1687  }
1688 
1689  // Verify query type
1690  if (m->has_querytype() && m->querytype() != protocol::qtINDIRECT)
1691  return badData("Invalid query type");
1692 
1693  // Verify query depth
1694  if (m->has_querydepth())
1695  {
1696  if (m->querydepth() > Tuning::maxQueryDepth ||
1697  itype == protocol::liBASE)
1698  {
1699  return badData("Invalid query depth");
1700  }
1701  }
1702 
1703  // Queue a job to process the request
1705  app_.getJobQueue().addJob(jtLEDGER_REQ, "recvGetLedger", [weak, m]() {
1706  if (auto peer = weak.lock())
1707  peer->processLedgerRequest(m);
1708  });
1709 }
1710 
1711 void
1713 {
1714  JLOG(p_journal_.trace()) << "onMessage, TMProofPathRequest";
1715  if (!ledgerReplayEnabled_)
1716  {
1718  return;
1719  }
1720 
1724  jtREPLAY_REQ, "recvProofPathRequest", [weak, m]() {
1725  if (auto peer = weak.lock())
1726  {
1727  auto reply =
1728  peer->ledgerReplayMsgHandler_.processProofPathRequest(m);
1729  if (reply.has_error())
1730  {
1731  if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1732  peer->charge(Resource::feeInvalidRequest);
1733  else
1734  peer->charge(Resource::feeRequestNoReply);
1735  }
1736  else
1737  {
1738  peer->send(std::make_shared<Message>(
1739  reply, protocol::mtPROOF_PATH_RESPONSE));
1740  }
1741  }
1742  });
1743 }
1744 
1745 void
1747 {
1748  if (!ledgerReplayEnabled_)
1749  {
1751  return;
1752  }
1753 
1755  {
1757  }
1758 }
1759 
1760 void
1762 {
1763  JLOG(p_journal_.trace()) << "onMessage, TMReplayDeltaRequest";
1764  if (!ledgerReplayEnabled_)
1765  {
1767  return;
1768  }
1769 
1773  jtREPLAY_REQ, "recvReplayDeltaRequest", [weak, m]() {
1774  if (auto peer = weak.lock())
1775  {
1776  auto reply =
1777  peer->ledgerReplayMsgHandler_.processReplayDeltaRequest(m);
1778  if (reply.has_error())
1779  {
1780  if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1781  peer->charge(Resource::feeInvalidRequest);
1782  else
1783  peer->charge(Resource::feeRequestNoReply);
1784  }
1785  else
1786  {
1787  peer->send(std::make_shared<Message>(
1788  reply, protocol::mtREPLAY_DELTA_RESPONSE));
1789  }
1790  }
1791  });
1792 }
1793 
1794 void
1796 {
1797  if (!ledgerReplayEnabled_)
1798  {
1800  return;
1801  }
1802 
1804  {
1806  }
1807 }
1808 
1809 void
1811 {
1812  auto badData = [&](std::string const& msg) {
1814  JLOG(p_journal_.warn()) << "TMLedgerData: " << msg;
1815  };
1816 
1817  // Verify ledger hash
1818  if (!stringIsUint256Sized(m->ledgerhash()))
1819  return badData("Invalid ledger hash");
1820 
1821  // Verify ledger sequence
1822  {
1823  auto const ledgerSeq{m->ledgerseq()};
1824  if (m->type() == protocol::liTS_CANDIDATE)
1825  {
1826  if (ledgerSeq != 0)
1827  {
1828  return badData(
1829  "Invalid ledger sequence " + std::to_string(ledgerSeq));
1830  }
1831  }
1832  else
1833  {
1834  // Verifying the network's earliest ledger only pertains to shards.
1835  if (app_.getShardStore() &&
1836  ledgerSeq < app_.getNodeStore().earliestLedgerSeq())
1837  {
1838  return badData(
1839  "Invalid ledger sequence " + std::to_string(ledgerSeq));
1840  }
1841 
1842  // Check if within a reasonable range
1843  using namespace std::chrono_literals;
1844  if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s &&
1845  ledgerSeq > app_.getLedgerMaster().getValidLedgerIndex() + 10)
1846  {
1847  return badData(
1848  "Invalid ledger sequence " + std::to_string(ledgerSeq));
1849  }
1850  }
1851  }
1852 
1853  // Verify ledger info type
1854  if (m->type() < protocol::liBASE || m->type() > protocol::liTS_CANDIDATE)
1855  return badData("Invalid ledger info type");
1856 
1857  // Verify reply error
1858  if (m->has_error() &&
1859  (m->error() < protocol::reNO_LEDGER ||
1860  m->error() > protocol::reBAD_REQUEST))
1861  {
1862  return badData("Invalid reply error");
1863  }
1864 
1865  // Verify ledger nodes.
1866  if (m->nodes_size() <= 0 || m->nodes_size() > Tuning::hardMaxReplyNodes)
1867  {
1868  return badData(
1869  "Invalid Ledger/TXset nodes " + std::to_string(m->nodes_size()));
1870  }
1871 
1872  // If there is a request cookie, attempt to relay the message
1873  if (m->has_requestcookie())
1874  {
1875  if (auto peer = overlay_.findPeerByShortID(m->requestcookie()))
1876  {
1877  m->clear_requestcookie();
1878  peer->send(std::make_shared<Message>(*m, protocol::mtLEDGER_DATA));
1879  }
1880  else
1881  {
1882  JLOG(p_journal_.info()) << "Unable to route TX/ledger data reply";
1883  }
1884  return;
1885  }
1886 
1887  uint256 const ledgerHash{m->ledgerhash()};
1888 
1889  // Otherwise check if received data for a candidate transaction set
1890  if (m->type() == protocol::liTS_CANDIDATE)
1891  {
1894  jtTXN_DATA, "recvPeerData", [weak, ledgerHash, m]() {
1895  if (auto peer = weak.lock())
1896  {
1897  peer->app_.getInboundTransactions().gotData(
1898  ledgerHash, peer, m);
1899  }
1900  });
1901  return;
1902  }
1903 
1904  // Consume the message
1906 }
1907 
1908 void
1910 {
1911  protocol::TMProposeSet& set = *m;
1912 
1913  auto const sig = makeSlice(set.signature());
1914 
1915  // Preliminary check for the validity of the signature: A DER encoded
1916  // signature can't be longer than 72 bytes.
1917  if ((std::clamp<std::size_t>(sig.size(), 64, 72) != sig.size()) ||
1918  (publicKeyType(makeSlice(set.nodepubkey())) != KeyType::secp256k1))
1919  {
1920  JLOG(p_journal_.warn()) << "Proposal: malformed";
1922  return;
1923  }
1924 
1925  if (!stringIsUint256Sized(set.currenttxhash()) ||
1926  !stringIsUint256Sized(set.previousledger()))
1927  {
1928  JLOG(p_journal_.warn()) << "Proposal: malformed";
1930  return;
1931  }
1932 
1933  // RH TODO: when isTrusted = false we should probably also cache a key
1934  // suppression for 30 seconds to avoid doing a relatively expensive lookup
1935  // every time a spam packet is received
1936  PublicKey const publicKey{makeSlice(set.nodepubkey())};
1937  auto const isTrusted = app_.validators().trusted(publicKey);
1938 
1939  // If the operator has specified that untrusted proposals be dropped then
1940  // this happens here I.e. before further wasting CPU verifying the signature
1941  // of an untrusted key
1942  if (!isTrusted && app_.config().RELAY_UNTRUSTED_PROPOSALS == -1)
1943  return;
1944 
1945  uint256 const proposeHash{set.currenttxhash()};
1946  uint256 const prevLedger{set.previousledger()};
1947 
1948  NetClock::time_point const closeTime{NetClock::duration{set.closetime()}};
1949 
1950  uint256 const suppression = proposalUniqueId(
1951  proposeHash,
1952  prevLedger,
1953  set.proposeseq(),
1954  closeTime,
1955  publicKey.slice(),
1956  sig);
1957 
1958  if (auto [added, relayed] =
1960  !added)
1961  {
1962  // Count unique messages (Slots has it's own 'HashRouter'), which a peer
1963  // receives within IDLED seconds since the message has been relayed.
1964  if (reduceRelayReady() && relayed &&
1965  (stopwatch().now() - *relayed) < reduce_relay::IDLED)
1967  suppression, publicKey, id_, protocol::mtPROPOSE_LEDGER);
1968  JLOG(p_journal_.trace()) << "Proposal: duplicate";
1969  return;
1970  }
1971 
1972  if (!isTrusted)
1973  {
1975  {
1976  JLOG(p_journal_.debug())
1977  << "Proposal: Dropping untrusted (peer divergence)";
1978  return;
1979  }
1980 
1981  if (!cluster() && app_.getFeeTrack().isLoadedLocal())
1982  {
1983  JLOG(p_journal_.debug()) << "Proposal: Dropping untrusted (load)";
1984  return;
1985  }
1986  }
1987 
1988  JLOG(p_journal_.trace())
1989  << "Proposal: " << (isTrusted ? "trusted" : "untrusted");
1990 
1991  auto proposal = RCLCxPeerPos(
1992  publicKey,
1993  sig,
1994  suppression,
1996  prevLedger,
1997  set.proposeseq(),
1998  proposeHash,
1999  closeTime,
2002 
2005  isTrusted ? jtPROPOSAL_t : jtPROPOSAL_ut,
2006  "recvPropose->checkPropose",
2007  [weak, isTrusted, m, proposal]() {
2008  if (auto peer = weak.lock())
2009  peer->checkPropose(isTrusted, m, proposal);
2010  });
2011 }
2012 
2013 void
2015 {
2016  JLOG(p_journal_.trace()) << "Status: Change";
2017 
2018  if (!m->has_networktime())
2019  m->set_networktime(app_.timeKeeper().now().time_since_epoch().count());
2020 
2021  {
2023  if (!last_status_.has_newstatus() || m->has_newstatus())
2024  last_status_ = *m;
2025  else
2026  {
2027  // preserve old status
2028  protocol::NodeStatus status = last_status_.newstatus();
2029  last_status_ = *m;
2030  m->set_newstatus(status);
2031  }
2032  }
2033 
2034  if (m->newevent() == protocol::neLOST_SYNC)
2035  {
2036  bool outOfSync{false};
2037  {
2038  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
2039  // guarded by recentLock_.
2041  if (!closedLedgerHash_.isZero())
2042  {
2043  outOfSync = true;
2045  }
2047  }
2048  if (outOfSync)
2049  {
2050  JLOG(p_journal_.debug()) << "Status: Out of sync";
2051  }
2052  return;
2053  }
2054 
2055  {
2056  uint256 closedLedgerHash{};
2057  bool const peerChangedLedgers{
2058  m->has_ledgerhash() && stringIsUint256Sized(m->ledgerhash())};
2059 
2060  {
2061  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
2062  // guarded by recentLock_.
2064  if (peerChangedLedgers)
2065  {
2066  closedLedgerHash_ = m->ledgerhash();
2067  closedLedgerHash = closedLedgerHash_;
2068  addLedger(closedLedgerHash, sl);
2069  }
2070  else
2071  {
2073  }
2074 
2075  if (m->has_ledgerhashprevious() &&
2076  stringIsUint256Sized(m->ledgerhashprevious()))
2077  {
2078  previousLedgerHash_ = m->ledgerhashprevious();
2080  }
2081  else
2082  {
2084  }
2085  }
2086  if (peerChangedLedgers)
2087  {
2088  JLOG(p_journal_.debug()) << "LCL is " << closedLedgerHash;
2089  }
2090  else
2091  {
2092  JLOG(p_journal_.debug()) << "Status: No ledger";
2093  }
2094  }
2095 
2096  if (m->has_firstseq() && m->has_lastseq())
2097  {
2099 
2100  minLedger_ = m->firstseq();
2101  maxLedger_ = m->lastseq();
2102 
2103  if ((maxLedger_ < minLedger_) || (minLedger_ == 0) || (maxLedger_ == 0))
2104  minLedger_ = maxLedger_ = 0;
2105  }
2106 
2107  if (m->has_ledgerseq() &&
2109  {
2110  checkTracking(
2111  m->ledgerseq(), app_.getLedgerMaster().getValidLedgerIndex());
2112  }
2113 
2114  app_.getOPs().pubPeerStatus([=, this]() -> Json::Value {
2116 
2117  if (m->has_newstatus())
2118  {
2119  switch (m->newstatus())
2120  {
2121  case protocol::nsCONNECTING:
2122  j[jss::status] = "CONNECTING";
2123  break;
2124  case protocol::nsCONNECTED:
2125  j[jss::status] = "CONNECTED";
2126  break;
2127  case protocol::nsMONITORING:
2128  j[jss::status] = "MONITORING";
2129  break;
2130  case protocol::nsVALIDATING:
2131  j[jss::status] = "VALIDATING";
2132  break;
2133  case protocol::nsSHUTTING:
2134  j[jss::status] = "SHUTTING";
2135  break;
2136  }
2137  }
2138 
2139  if (m->has_newevent())
2140  {
2141  switch (m->newevent())
2142  {
2143  case protocol::neCLOSING_LEDGER:
2144  j[jss::action] = "CLOSING_LEDGER";
2145  break;
2146  case protocol::neACCEPTED_LEDGER:
2147  j[jss::action] = "ACCEPTED_LEDGER";
2148  break;
2149  case protocol::neSWITCHED_LEDGER:
2150  j[jss::action] = "SWITCHED_LEDGER";
2151  break;
2152  case protocol::neLOST_SYNC:
2153  j[jss::action] = "LOST_SYNC";
2154  break;
2155  }
2156  }
2157 
2158  if (m->has_ledgerseq())
2159  {
2160  j[jss::ledger_index] = m->ledgerseq();
2161  }
2162 
2163  if (m->has_ledgerhash())
2164  {
2165  uint256 closedLedgerHash{};
2166  {
2167  std::lock_guard sl(recentLock_);
2168  closedLedgerHash = closedLedgerHash_;
2169  }
2170  j[jss::ledger_hash] = to_string(closedLedgerHash);
2171  }
2172 
2173  if (m->has_networktime())
2174  {
2175  j[jss::date] = Json::UInt(m->networktime());
2176  }
2177 
2178  if (m->has_firstseq() && m->has_lastseq())
2179  {
2180  j[jss::ledger_index_min] = Json::UInt(m->firstseq());
2181  j[jss::ledger_index_max] = Json::UInt(m->lastseq());
2182  }
2183 
2184  return j;
2185  });
2186 }
2187 
2188 void
2189 PeerImp::checkTracking(std::uint32_t validationSeq)
2190 {
2191  std::uint32_t serverSeq;
2192  {
2193  // Extract the sequence number of the highest
2194  // ledger this peer has
2195  std::lock_guard sl(recentLock_);
2196 
2197  serverSeq = maxLedger_;
2198  }
2199  if (serverSeq != 0)
2200  {
2201  // Compare the peer's ledger sequence to the
2202  // sequence of a recently-validated ledger
2203  checkTracking(serverSeq, validationSeq);
2204  }
2205 }
2206 
2207 void
2208 PeerImp::checkTracking(std::uint32_t seq1, std::uint32_t seq2)
2209 {
2210  int diff = std::max(seq1, seq2) - std::min(seq1, seq2);
2211 
2212  if (diff < Tuning::convergedLedgerLimit)
2213  {
2214  // The peer's ledger sequence is close to the validation's
2215  tracking_ = Tracking::converged;
2216  }
2217 
2218  if ((diff > Tuning::divergedLedgerLimit) &&
2219  (tracking_.load() != Tracking::diverged))
2220  {
2221  // The peer's ledger sequence is way off the validation's
2222  std::lock_guard sl(recentLock_);
2223 
2224  tracking_ = Tracking::diverged;
2225  trackingTime_ = clock_type::now();
2226  }
2227 }
2228 
2229 void
2231 {
2232  if (!stringIsUint256Sized(m->hash()))
2233  {
2234  fee_ = Resource::feeInvalidRequest;
2235  return;
2236  }
2237 
2238  uint256 const hash{m->hash()};
2239 
2240  if (m->status() == protocol::tsHAVE)
2241  {
2242  std::lock_guard sl(recentLock_);
2243 
2244  if (std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
2245  recentTxSets_.end())
2246  {
2247  fee_ = Resource::feeUnwantedData;
2248  return;
2249  }
2250 
2251  recentTxSets_.push_back(hash);
2252  }
2253 }
2254 
2255 void
2256 PeerImp::onValidatorListMessage(
2257  std::string const& messageType,
2258  std::string const& manifest,
2259  std::uint32_t version,
2260  std::vector<ValidatorBlobInfo> const& blobs)
2261 {
2262  // If there are no blobs, the message is malformed (possibly because of
2263  // ValidatorList class rules), so charge accordingly and skip processing.
2264  if (blobs.empty())
2265  {
2266  JLOG(p_journal_.warn()) << "Ignored malformed " << messageType
2267  << " from peer " << remote_address_;
2268  // This shouldn't ever happen with a well-behaved peer
2269  fee_ = Resource::feeHighBurdenPeer;
2270  return;
2271  }
2272 
2273  auto const hash = sha512Half(manifest, blobs, version);
2274 
2275  JLOG(p_journal_.debug())
2276  << "Received " << messageType << " from " << remote_address_.to_string()
2277  << " (" << id_ << ")";
2278 
2279  if (!app_.getHashRouter().addSuppressionPeer(hash, id_))
2280  {
2281  JLOG(p_journal_.debug())
2282  << messageType << ": received duplicate " << messageType;
2283  // Charging this fee here won't hurt the peer in the normal
2284  // course of operation (ie. refresh every 5 minutes), but
2285  // will add up if the peer is misbehaving.
2286  fee_ = Resource::feeUnwantedData;
2287  return;
2288  }
2289 
2290  auto const applyResult = app_.validators().applyListsAndBroadcast(
2291  manifest,
2292  version,
2293  blobs,
2294  remote_address_.to_string(),
2295  hash,
2296  app_.overlay(),
2297  app_.getHashRouter(),
2298  app_.getOPs());
2299 
2300  JLOG(p_journal_.debug())
2301  << "Processed " << messageType << " version " << version << " from "
2302  << (applyResult.publisherKey ? strHex(*applyResult.publisherKey)
2303  : "unknown or invalid publisher")
2304  << " from " << remote_address_.to_string() << " (" << id_
2305  << ") with best result " << to_string(applyResult.bestDisposition());
2306 
2307  // Act based on the best result
2308  switch (applyResult.bestDisposition())
2309  {
2310  // New list
2311  case ListDisposition::accepted:
2312  // Newest list is expired, and that needs to be broadcast, too
2313  case ListDisposition::expired:
2314  // Future list
2315  case ListDisposition::pending: {
2316  std::lock_guard<std::mutex> sl(recentLock_);
2317 
2318  assert(applyResult.publisherKey);
2319  auto const& pubKey = *applyResult.publisherKey;
2320 #ifndef NDEBUG
2321  if (auto const iter = publisherListSequences_.find(pubKey);
2322  iter != publisherListSequences_.end())
2323  {
2324  assert(iter->second < applyResult.sequence);
2325  }
2326 #endif
2327  publisherListSequences_[pubKey] = applyResult.sequence;
2328  }
2329  break;
2330  case ListDisposition::same_sequence:
2331  case ListDisposition::known_sequence:
2332 #ifndef NDEBUG
2333  {
2334  std::lock_guard<std::mutex> sl(recentLock_);
2335  assert(applyResult.sequence && applyResult.publisherKey);
2336  assert(
2337  publisherListSequences_[*applyResult.publisherKey] <=
2338  applyResult.sequence);
2339  }
2340 #endif // !NDEBUG
2341 
2342  break;
2343  case ListDisposition::stale:
2344  case ListDisposition::untrusted:
2345  case ListDisposition::invalid:
2346  case ListDisposition::unsupported_version:
2347  break;
2348  default:
2349  assert(false);
2350  }
2351 
2352  // Charge based on the worst result
2353  switch (applyResult.worstDisposition())
2354  {
2355  case ListDisposition::accepted:
2356  case ListDisposition::expired:
2357  case ListDisposition::pending:
2358  // No charges for good data
2359  break;
2360  case ListDisposition::same_sequence:
2361  case ListDisposition::known_sequence:
2362  // Charging this fee here won't hurt the peer in the normal
2363  // course of operation (ie. refresh every 5 minutes), but
2364  // will add up if the peer is misbehaving.
2365  fee_ = Resource::feeUnwantedData;
2366  break;
2367  case ListDisposition::stale:
2368  // There are very few good reasons for a peer to send an
2369  // old list, particularly more than once.
2370  fee_ = Resource::feeBadData;
2371  break;
2372  case ListDisposition::untrusted:
2373  // Charging this fee here won't hurt the peer in the normal
2374  // course of operation (ie. refresh every 5 minutes), but
2375  // will add up if the peer is misbehaving.
2376  fee_ = Resource::feeUnwantedData;
2377  break;
2378  case ListDisposition::invalid:
2379  // This shouldn't ever happen with a well-behaved peer
2380  fee_ = Resource::feeInvalidSignature;
2381  break;
2382  case ListDisposition::unsupported_version:
2383  // During a version transition, this may be legitimate.
2384  // If it happens frequently, that's probably bad.
2385  fee_ = Resource::feeBadData;
2386  break;
2387  default:
2388  assert(false);
2389  }
2390 
2391  // Log based on all the results.
2392  for (auto const& [disp, count] : applyResult.dispositions)
2393  {
2394  switch (disp)
2395  {
2396  // New list
2397  case ListDisposition::accepted:
2398  JLOG(p_journal_.debug())
2399  << "Applied " << count << " new " << messageType
2400  << "(s) from peer " << remote_address_;
2401  break;
2402  // Newest list is expired, and that needs to be broadcast, too
2403  case ListDisposition::expired:
2404  JLOG(p_journal_.debug())
2405  << "Applied " << count << " expired " << messageType
2406  << "(s) from peer " << remote_address_;
2407  break;
2408  // Future list
2409  case ListDisposition::pending:
2410  JLOG(p_journal_.debug())
2411  << "Processed " << count << " future " << messageType
2412  << "(s) from peer " << remote_address_;
2413  break;
2414  case ListDisposition::same_sequence:
2415  JLOG(p_journal_.warn())
2416  << "Ignored " << count << " " << messageType
2417  << "(s) with current sequence from peer "
2418  << remote_address_;
2419  break;
2420  case ListDisposition::known_sequence:
2421  JLOG(p_journal_.warn())
2422  << "Ignored " << count << " " << messageType
2423  << "(s) with future sequence from peer " << remote_address_;
2424  break;
2425  case ListDisposition::stale:
2426  JLOG(p_journal_.warn())
2427  << "Ignored " << count << "stale " << messageType
2428  << "(s) from peer " << remote_address_;
2429  break;
2430  case ListDisposition::untrusted:
2431  JLOG(p_journal_.warn())
2432  << "Ignored " << count << " untrusted " << messageType
2433  << "(s) from peer " << remote_address_;
2434  break;
2435  case ListDisposition::unsupported_version:
2436  JLOG(p_journal_.warn())
2437  << "Ignored " << count << "unsupported version "
2438  << messageType << "(s) from peer " << remote_address_;
2439  break;
2440  case ListDisposition::invalid:
2441  JLOG(p_journal_.warn())
2442  << "Ignored " << count << "invalid " << messageType
2443  << "(s) from peer " << remote_address_;
2444  break;
2445  default:
2446  assert(false);
2447  }
2448  }
2449 }
2450 
2451 void
2453 {
2454  try
2455  {
2456  if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
2457  {
2458  JLOG(p_journal_.debug())
2459  << "ValidatorList: received validator list from peer using "
2460  << "protocol version " << to_string(protocol_)
2461  << " which shouldn't support this feature.";
2462  fee_ = Resource::feeUnwantedData;
2463  return;
2464  }
2465  onValidatorListMessage(
2466  "ValidatorList",
2467  m->manifest(),
2468  m->version(),
2469  ValidatorList::parseBlobs(*m));
2470  }
2471  catch (std::exception const& e)
2472  {
2473  JLOG(p_journal_.warn()) << "ValidatorList: Exception, " << e.what()
2474  << " from peer " << remote_address_;
2475  fee_ = Resource::feeBadData;
2476  }
2477 }
2478 
2479 void
2480 PeerImp::onMessage(
2482 {
2483  try
2484  {
2485  if (!supportsFeature(ProtocolFeature::ValidatorList2Propagation))
2486  {
2487  JLOG(p_journal_.debug())
2488  << "ValidatorListCollection: received validator list from peer "
2489  << "using protocol version " << to_string(protocol_)
2490  << " which shouldn't support this feature.";
2491  fee_ = Resource::feeUnwantedData;
2492  return;
2493  }
2494  else if (m->version() < 2)
2495  {
2496  JLOG(p_journal_.debug())
2497  << "ValidatorListCollection: received invalid validator list "
2498  "version "
2499  << m->version() << " from peer using protocol version "
2500  << to_string(protocol_);
2501  fee_ = Resource::feeBadData;
2502  return;
2503  }
2504  onValidatorListMessage(
2505  "ValidatorListCollection",
2506  m->manifest(),
2507  m->version(),
2508  ValidatorList::parseBlobs(*m));
2509  }
2510  catch (std::exception const& e)
2511  {
2512  JLOG(p_journal_.warn()) << "ValidatorListCollection: Exception, "
2513  << e.what() << " from peer " << remote_address_;
2514  fee_ = Resource::feeBadData;
2515  }
2516 }
2517 
2518 void
2519 PeerImp::onMessage(std::shared_ptr<protocol::TMValidation> const& m)
2520 {
2521  if (m->validation().size() < 50)
2522  {
2523  JLOG(p_journal_.warn()) << "Validation: Too small";
2524  fee_ = Resource::feeInvalidRequest;
2525  return;
2526  }
2527 
2528  try
2529  {
2530  auto const closeTime = app_.timeKeeper().closeTime();
2531 
2533  {
2534  SerialIter sit(makeSlice(m->validation()));
2535  val = std::make_shared<STValidation>(
2536  std::ref(sit),
2537  [this](PublicKey const& pk) {
2538  return calcNodeID(
2539  app_.validatorManifests().getMasterKey(pk));
2540  },
2541  false);
2542  val->setSeen(closeTime);
2543  }
2544 
2545  if (!isCurrent(
2546  app_.getValidations().parms(),
2547  app_.timeKeeper().closeTime(),
2548  val->getSignTime(),
2549  val->getSeenTime()))
2550  {
2551  JLOG(p_journal_.trace()) << "Validation: Not current";
2552  fee_ = Resource::feeUnwantedData;
2553  return;
2554  }
2555 
2556  // RH TODO: when isTrusted = false we should probably also cache a key
2557  // suppression for 30 seconds to avoid doing a relatively expensive
2558  // lookup every time a spam packet is received
2559  auto const isTrusted =
2560  app_.validators().trusted(val->getSignerPublic());
2561 
2562  // If the operator has specified that untrusted validations be dropped
2563  // then this happens here I.e. before further wasting CPU verifying the
2564  // signature of an untrusted key
2565  if (!isTrusted && app_.config().RELAY_UNTRUSTED_VALIDATIONS == -1)
2566  return;
2567 
2568  auto key = sha512Half(makeSlice(m->validation()));
2569 
2570  if (auto [added, relayed] =
2571  app_.getHashRouter().addSuppressionPeerWithStatus(key, id_);
2572  !added)
2573  {
2574  // Count unique messages (Slots has it's own 'HashRouter'), which a
2575  // peer receives within IDLED seconds since the message has been
2576  // relayed. Wait WAIT_ON_BOOTUP time to let the server establish
2577  // connections to peers.
2578  if (reduceRelayReady() && relayed &&
2579  (stopwatch().now() - *relayed) < reduce_relay::IDLED)
2580  overlay_.updateSlotAndSquelch(
2581  key, val->getSignerPublic(), id_, protocol::mtVALIDATION);
2582  JLOG(p_journal_.trace()) << "Validation: duplicate";
2583  return;
2584  }
2585 
2586  if (!isTrusted && (tracking_.load() == Tracking::diverged))
2587  {
2588  JLOG(p_journal_.debug())
2589  << "Dropping untrusted validation from diverged peer";
2590  }
2591  else if (isTrusted || !app_.getFeeTrack().isLoadedLocal())
2592  {
2593  std::string const name = [isTrusted, val]() {
2594  std::string ret =
2595  isTrusted ? "Trusted validation" : "Untrusted validation";
2596 
2597 #ifdef DEBUG
2598  ret += " " +
2599  std::to_string(val->getFieldU32(sfLedgerSequence)) + ": " +
2600  to_string(val->getNodeID());
2601 #endif
2602 
2603  return ret;
2604  }();
2605 
2606  std::weak_ptr<PeerImp> weak = shared_from_this();
2607  app_.getJobQueue().addJob(
2608  isTrusted ? jtVALIDATION_t : jtVALIDATION_ut,
2609  name,
2610  [weak, val, m, key]() {
2611  if (auto peer = weak.lock())
2612  peer->checkValidation(val, key, m);
2613  });
2614  }
2615  else
2616  {
2617  JLOG(p_journal_.debug())
2618  << "Dropping untrusted validation for load";
2619  }
2620  }
2621  catch (std::exception const& e)
2622  {
2623  JLOG(p_journal_.warn())
2624  << "Exception processing validation: " << e.what();
2625  fee_ = Resource::feeInvalidRequest;
2626  }
2627 }
2628 
2629 void
2631 {
2632  protocol::TMGetObjectByHash& packet = *m;
2633 
2634  JLOG(p_journal_.trace()) << "received TMGetObjectByHash " << packet.type()
2635  << " " << packet.objects_size();
2636 
2637  if (packet.query())
2638  {
2639  // this is a query
2640  if (send_queue_.size() >= Tuning::dropSendQueue)
2641  {
2642  JLOG(p_journal_.debug()) << "GetObject: Large send queue";
2643  return;
2644  }
2645 
2646  if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2647  {
2648  doFetchPack(m);
2649  return;
2650  }
2651 
2652  if (packet.type() == protocol::TMGetObjectByHash::otTRANSACTIONS)
2653  {
2654  if (!txReduceRelayEnabled())
2655  {
2656  JLOG(p_journal_.error())
2657  << "TMGetObjectByHash: tx reduce-relay is disabled";
2658  fee_ = Resource::feeInvalidRequest;
2659  return;
2660  }
2661 
2662  std::weak_ptr<PeerImp> weak = shared_from_this();
2663  app_.getJobQueue().addJob(
2664  jtREQUESTED_TXN, "doTransactions", [weak, m]() {
2665  if (auto peer = weak.lock())
2666  peer->doTransactions(m);
2667  });
2668  return;
2669  }
2670 
2671  fee_ = Resource::feeMediumBurdenPeer;
2672 
2673  protocol::TMGetObjectByHash reply;
2674 
2675  reply.set_query(false);
2676 
2677  if (packet.has_seq())
2678  reply.set_seq(packet.seq());
2679 
2680  reply.set_type(packet.type());
2681 
2682  if (packet.has_ledgerhash())
2683  {
2684  if (!stringIsUint256Sized(packet.ledgerhash()))
2685  {
2686  fee_ = Resource::feeInvalidRequest;
2687  return;
2688  }
2689 
2690  reply.set_ledgerhash(packet.ledgerhash());
2691  }
2692 
2693  // This is a very minimal implementation
2694  for (int i = 0; i < packet.objects_size(); ++i)
2695  {
2696  auto const& obj = packet.objects(i);
2697  if (obj.has_hash() && stringIsUint256Sized(obj.hash()))
2698  {
2699  uint256 const hash{obj.hash()};
2700  // VFALCO TODO Move this someplace more sensible so we dont
2701  // need to inject the NodeStore interfaces.
2702  std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2703  auto nodeObject{app_.getNodeStore().fetchNodeObject(hash, seq)};
2704  if (!nodeObject)
2705  {
2706  if (auto shardStore = app_.getShardStore())
2707  {
2708  if (seq >= shardStore->earliestLedgerSeq())
2709  nodeObject = shardStore->fetchNodeObject(hash, seq);
2710  }
2711  }
2712  if (nodeObject)
2713  {
2714  protocol::TMIndexedObject& newObj = *reply.add_objects();
2715  newObj.set_hash(hash.begin(), hash.size());
2716  newObj.set_data(
2717  &nodeObject->getData().front(),
2718  nodeObject->getData().size());
2719 
2720  if (obj.has_nodeid())
2721  newObj.set_index(obj.nodeid());
2722  if (obj.has_ledgerseq())
2723  newObj.set_ledgerseq(obj.ledgerseq());
2724 
2725  // VFALCO NOTE "seq" in the message is obsolete
2726  }
2727  }
2728  }
2729 
2730  JLOG(p_journal_.trace()) << "GetObj: " << reply.objects_size() << " of "
2731  << packet.objects_size();
2732  send(std::make_shared<Message>(reply, protocol::mtGET_OBJECTS));
2733  }
2734  else
2735  {
2736  // this is a reply
2737  std::uint32_t pLSeq = 0;
2738  bool pLDo = true;
2739  bool progress = false;
2740 
2741  for (int i = 0; i < packet.objects_size(); ++i)
2742  {
2743  const protocol::TMIndexedObject& obj = packet.objects(i);
2744 
2745  if (obj.has_hash() && stringIsUint256Sized(obj.hash()))
2746  {
2747  if (obj.has_ledgerseq())
2748  {
2749  if (obj.ledgerseq() != pLSeq)
2750  {
2751  if (pLDo && (pLSeq != 0))
2752  {
2753  JLOG(p_journal_.debug())
2754  << "GetObj: Full fetch pack for " << pLSeq;
2755  }
2756  pLSeq = obj.ledgerseq();
2757  pLDo = !app_.getLedgerMaster().haveLedger(pLSeq);
2758 
2759  if (!pLDo)
2760  {
2761  JLOG(p_journal_.debug())
2762  << "GetObj: Late fetch pack for " << pLSeq;
2763  }
2764  else
2765  progress = true;
2766  }
2767  }
2768 
2769  if (pLDo)
2770  {
2771  uint256 const hash{obj.hash()};
2772 
2773  app_.getLedgerMaster().addFetchPack(
2774  hash,
2775  std::make_shared<Blob>(
2776  obj.data().begin(), obj.data().end()));
2777  }
2778  }
2779  }
2780 
2781  if (pLDo && (pLSeq != 0))
2782  {
2783  JLOG(p_journal_.debug())
2784  << "GetObj: Partial fetch pack for " << pLSeq;
2785  }
2786  if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2787  app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2788  }
2789 }
2790 
2791 void
2793 {
2794  if (!txReduceRelayEnabled())
2795  {
2796  JLOG(p_journal_.error())
2797  << "TMHaveTransactions: tx reduce-relay is disabled";
2798  fee_ = Resource::feeInvalidRequest;
2799  return;
2800  }
2801 
2802  std::weak_ptr<PeerImp> weak = shared_from_this();
2803  app_.getJobQueue().addJob(
2804  jtMISSING_TXN, "handleHaveTransactions", [weak, m]() {
2805  if (auto peer = weak.lock())
2806  peer->handleHaveTransactions(m);
2807  });
2808 }
2809 
2810 void
2811 PeerImp::handleHaveTransactions(
2813 {
2814  protocol::TMGetObjectByHash tmBH;
2815  tmBH.set_type(protocol::TMGetObjectByHash_ObjectType_otTRANSACTIONS);
2816  tmBH.set_query(true);
2817 
2818  JLOG(p_journal_.trace())
2819  << "received TMHaveTransactions " << m->hashes_size();
2820 
2821  for (std::uint32_t i = 0; i < m->hashes_size(); i++)
2822  {
2823  if (!stringIsUint256Sized(m->hashes(i)))
2824  {
2825  JLOG(p_journal_.error())
2826  << "TMHaveTransactions with invalid hash size";
2827  fee_ = Resource::feeInvalidRequest;
2828  return;
2829  }
2830 
2831  uint256 hash(m->hashes(i));
2832 
2833  auto txn = app_.getMasterTransaction().fetch_from_cache(hash);
2834 
2835  JLOG(p_journal_.trace()) << "checking transaction " << (bool)txn;
2836 
2837  if (!txn)
2838  {
2839  JLOG(p_journal_.debug()) << "adding transaction to request";
2840 
2841  auto obj = tmBH.add_objects();
2842  obj->set_hash(hash.data(), hash.size());
2843  }
2844  else
2845  {
2846  // Erase only if a peer has seen this tx. If the peer has not
2847  // seen this tx then the tx could not has been queued for this
2848  // peer.
2849  removeTxQueue(hash);
2850  }
2851  }
2852 
2853  JLOG(p_journal_.trace())
2854  << "transaction request object is " << tmBH.objects_size();
2855 
2856  if (tmBH.objects_size() > 0)
2857  send(std::make_shared<Message>(tmBH, protocol::mtGET_OBJECTS));
2858 }
2859 
2860 void
2861 PeerImp::onMessage(std::shared_ptr<protocol::TMTransactions> const& m)
2862 {
2863  if (!txReduceRelayEnabled())
2864  {
2865  JLOG(p_journal_.error())
2866  << "TMTransactions: tx reduce-relay is disabled";
2867  fee_ = Resource::feeInvalidRequest;
2868  return;
2869  }
2870 
2871  JLOG(p_journal_.trace())
2872  << "received TMTransactions " << m->transactions_size();
2873 
2874  overlay_.addTxMetrics(m->transactions_size());
2875 
2876  for (std::uint32_t i = 0; i < m->transactions_size(); ++i)
2877  handleTransaction(
2879  m->mutable_transactions(i), [](protocol::TMTransaction*) {}),
2880  false);
2881 }
2882 
2883 void
2884 PeerImp::onMessage(std::shared_ptr<protocol::TMSquelch> const& m)
2885 {
2886  using on_message_fn =
2888  if (!strand_.running_in_this_thread())
2889  return post(
2890  strand_,
2891  std::bind(
2892  (on_message_fn)&PeerImp::onMessage, shared_from_this(), m));
2893 
2894  if (!m->has_validatorpubkey())
2895  {
2896  charge(Resource::feeBadData);
2897  return;
2898  }
2899  auto validator = m->validatorpubkey();
2900  auto const slice{makeSlice(validator)};
2901  if (!publicKeyType(slice))
2902  {
2903  charge(Resource::feeBadData);
2904  return;
2905  }
2906  PublicKey key(slice);
2907 
2908  // Ignore non-validator squelch
2909  if (!app_.validators().listed(key))
2910  {
2911  charge(Resource::feeBadData);
2912  JLOG(p_journal_.debug())
2913  << "onMessage: TMSquelch discarding non-validator squelch "
2914  << slice;
2915  return;
2916  }
2917 
2918  // Ignore the squelch for validator's own messages.
2919  if (key == app_.getValidationPublicKey())
2920  {
2921  JLOG(p_journal_.debug())
2922  << "onMessage: TMSquelch discarding validator's squelch " << slice;
2923  return;
2924  }
2925 
2926  std::uint32_t duration =
2927  m->has_squelchduration() ? m->squelchduration() : 0;
2928  if (!m->squelch())
2929  squelch_.removeSquelch(key);
2930  else if (!squelch_.addSquelch(key, std::chrono::seconds{duration}))
2931  charge(Resource::feeBadData);
2932 
2933  JLOG(p_journal_.debug())
2934  << "onMessage: TMSquelch " << slice << " " << id() << " " << duration;
2935 }
2936 
2937 void
2938 PeerImp::onStartProtocol()
2939 {
2940  JLOG(journal_.debug()) << "onStartProtocol(): " << remote_address_;
2941  // Send all the validator lists that have been loaded
2942  if (supportsFeature(ProtocolFeature::ValidatorListPropagation))
2943  {
2944  app_.validators().for_each_available(
2945  [&](std::string const& manifest,
2946  std::uint32_t version,
2948  PublicKey const& pubKey,
2949  std::size_t maxSequence,
2950  uint256 const& hash) {
2951  ValidatorList::sendValidatorList(
2952  *this,
2953  0,
2954  pubKey,
2955  maxSequence,
2956  version,
2957  manifest,
2958  blobInfos,
2959  app_.getHashRouter(),
2960  p_journal_);
2961 
2962  // Don't send it next time.
2963  app_.getHashRouter().addSuppressionPeer(hash, id_);
2964  });
2965  }
2966 
2967  if (auto m = overlay_.getManifestsMessage())
2968  send(m);
2969 
2970  // Request shard info from peer
2971  protocol::TMGetPeerShardInfoV2 tmGPS;
2972  tmGPS.set_relays(0);
2973  send(std::make_shared<Message>(tmGPS, protocol::mtGET_PEER_SHARD_INFO_V2));
2974 }
2975 
2976 void
2978 {
2979  JLOG(journal_.debug()) << "onMessage(TMStartProtocol): " << remote_address_;
2980  onStartProtocol();
2981 }
2982 
2983 void
2985 {
2986  using on_message_fn =
2988  if (!strand_.running_in_this_thread())
2989  return post(
2990  strand_,
2991  std::bind(
2992  (on_message_fn)&PeerImp::onMessage, shared_from_this(), m));
2993 
2994  JLOG(journal_.info()) << "got graceful close from: " << remote_address_
2995  << " reason: " << closeReasonToString(m->reason());
2996 
2997  close();
2998 }
2999 
3000 //--------------------------------------------------------------------------
3001 
3002 void
3003 PeerImp::addLedger(
3004  uint256 const& hash,
3005  std::lock_guard<std::mutex> const& lockedRecentLock)
3006 {
3007  // lockedRecentLock is passed as a reminder that recentLock_ must be
3008  // locked by the caller.
3009  (void)lockedRecentLock;
3010 
3011  if (std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
3012  recentLedgers_.end())
3013  return;
3014 
3015  recentLedgers_.push_back(hash);
3016 }
3017 
3018 void
3019 PeerImp::doFetchPack(const std::shared_ptr<protocol::TMGetObjectByHash>& packet)
3020 {
3021  // VFALCO TODO Invert this dependency using an observer and shared state
3022  // object. Don't queue fetch pack jobs if we're under load or we already
3023  // have some queued.
3024  if (app_.getFeeTrack().isLoadedLocal() ||
3025  (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
3026  (app_.getJobQueue().getJobCount(jtPACK) > 10))
3027  {
3028  JLOG(p_journal_.info()) << "Too busy to make fetch pack";
3029  return;
3030  }
3031 
3032  if (!stringIsUint256Sized(packet->ledgerhash()))
3033  {
3034  JLOG(p_journal_.warn()) << "FetchPack hash size malformed";
3035  fee_ = Resource::feeInvalidRequest;
3036  return;
3037  }
3038 
3039  fee_ = Resource::feeHighBurdenPeer;
3040 
3041  uint256 const hash{packet->ledgerhash()};
3042 
3043  std::weak_ptr<PeerImp> weak = shared_from_this();
3044  auto elapsed = UptimeClock::now();
3045  auto const pap = &app_;
3046  app_.getJobQueue().addJob(
3047  jtPACK, "MakeFetchPack", [pap, weak, packet, hash, elapsed]() {
3048  pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
3049  });
3050 }
3051 
3052 void
3053 PeerImp::doTransactions(
3055 {
3056  protocol::TMTransactions reply;
3057 
3058  JLOG(p_journal_.trace()) << "received TMGetObjectByHash requesting tx "
3059  << packet->objects_size();
3060 
3061  if (packet->objects_size() > reduce_relay::MAX_TX_QUEUE_SIZE)
3062  {
3063  JLOG(p_journal_.error()) << "doTransactions, invalid number of hashes";
3064  fee_ = Resource::feeInvalidRequest;
3065  return;
3066  }
3067 
3068  for (std::uint32_t i = 0; i < packet->objects_size(); ++i)
3069  {
3070  auto const& obj = packet->objects(i);
3071 
3072  if (!stringIsUint256Sized(obj.hash()))
3073  {
3074  fee_ = Resource::feeInvalidRequest;
3075  return;
3076  }
3077 
3078  uint256 hash(obj.hash());
3079 
3080  auto txn = app_.getMasterTransaction().fetch_from_cache(hash);
3081 
3082  if (!txn)
3083  {
3084  JLOG(p_journal_.error()) << "doTransactions, transaction not found "
3085  << Slice(hash.data(), hash.size());
3086  fee_ = Resource::feeInvalidRequest;
3087  return;
3088  }
3089 
3090  Serializer s;
3091  auto tx = reply.add_transactions();
3092  auto sttx = txn->getSTransaction();
3093  sttx->add(s);
3094  tx->set_rawtransaction(s.data(), s.size());
3095  tx->set_status(
3096  txn->getStatus() == INCLUDED ? protocol::tsCURRENT
3097  : protocol::tsNEW);
3098  tx->set_receivetimestamp(
3099  app_.timeKeeper().now().time_since_epoch().count());
3100  tx->set_deferred(txn->getSubmitResult().queued);
3101  }
3102 
3103  if (reply.transactions_size() > 0)
3104  send(std::make_shared<Message>(reply, protocol::mtTRANSACTIONS));
3105 }
3106 
3107 void
3108 PeerImp::checkTransaction(
3109  int flags,
3110  bool checkSignature,
3111  std::shared_ptr<STTx const> const& stx)
3112 {
3113  // VFALCO TODO Rewrite to not use exceptions
3114  try
3115  {
3116  // Expired?
3117  if (stx->isFieldPresent(sfLastLedgerSequence) &&
3118  (stx->getFieldU32(sfLastLedgerSequence) <
3119  app_.getLedgerMaster().getValidLedgerIndex()))
3120  {
3121  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
3122  charge(Resource::feeUnwantedData);
3123  return;
3124  }
3125 
3126  if (checkSignature)
3127  {
3128  // Check the signature before handing off to the job queue.
3129  if (auto [valid, validReason] = checkValidity(
3130  app_.getHashRouter(),
3131  *stx,
3132  app_.getLedgerMaster().getValidatedRules(),
3133  app_.config());
3134  valid != Validity::Valid)
3135  {
3136  if (!validReason.empty())
3137  {
3138  JLOG(p_journal_.trace())
3139  << "Exception checking transaction: " << validReason;
3140  }
3141 
3142  // Probably not necessary to set SF_BAD, but doesn't hurt.
3143  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
3144  charge(Resource::feeInvalidSignature);
3145  return;
3146  }
3147  }
3148  else
3149  {
3150  forceValidity(
3151  app_.getHashRouter(), stx->getTransactionID(), Validity::Valid);
3152  }
3153 
3154  std::string reason;
3155  auto tx = std::make_shared<Transaction>(stx, reason, app_);
3156 
3157  if (tx->getStatus() == INVALID)
3158  {
3159  if (!reason.empty())
3160  {
3161  JLOG(p_journal_.trace())
3162  << "Exception checking transaction: " << reason;
3163  }
3164  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
3165  charge(Resource::feeInvalidSignature);
3166  return;
3167  }
3168 
3169  bool const trusted(flags & SF_TRUSTED);
3170  app_.getOPs().processTransaction(
3171  tx,
3172  trusted,
3173  RPC::SubmitSync::async,
3174  false,
3175  NetworkOPs::FailHard::no);
3176  }
3177  catch (std::exception const& ex)
3178  {
3179  JLOG(p_journal_.warn())
3180  << "Exception in " << __func__ << ": " << ex.what();
3181  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
3182  charge(Resource::feeBadData);
3183  }
3184 }
3185 
3186 // Called from our JobQueue
3187 void
3188 PeerImp::checkPropose(
3189  bool isTrusted,
3191  RCLCxPeerPos peerPos)
3192 {
3193  JLOG(p_journal_.trace())
3194  << "Checking " << (isTrusted ? "trusted" : "UNTRUSTED") << " proposal";
3195 
3196  assert(packet);
3197 
3198  if (!cluster() && !peerPos.checkSign())
3199  {
3200  JLOG(p_journal_.warn()) << "Proposal fails sig check";
3201  charge(Resource::feeInvalidSignature);
3202  return;
3203  }
3204 
3205  bool relay;
3206 
3207  if (isTrusted)
3208  relay = app_.getOPs().processTrustedProposal(peerPos);
3209  else
3210  relay = app_.config().RELAY_UNTRUSTED_PROPOSALS == 1 || cluster();
3211 
3212  if (relay)
3213  {
3214  // haveMessage contains peers, which are suppressed; i.e. the peers
3215  // are the source of the message, consequently the message should
3216  // not be relayed to these peers. But the message must be counted
3217  // as part of the squelch logic.
3218  auto haveMessage = app_.overlay().relay(
3219  *packet, peerPos.suppressionID(), peerPos.publicKey());
3220  if (reduceRelayReady() && !haveMessage.empty())
3221  overlay_.updateSlotAndSquelch(
3222  peerPos.suppressionID(),
3223  peerPos.publicKey(),
3224  std::move(haveMessage),
3225  protocol::mtPROPOSE_LEDGER);
3226  }
3227 }
3228 
3229 void
3230 PeerImp::checkValidation(
3231  std::shared_ptr<STValidation> const& val,
3232  uint256 const& key,
3234 {
3235  if (!val->isValid())
3236  {
3237  JLOG(p_journal_.debug()) << "Validation forwarded by peer is invalid";
3238  charge(Resource::feeInvalidSignature);
3239  return;
3240  }
3241 
3242  // FIXME it should be safe to remove this try/catch. Investigate codepaths.
3243  try
3244  {
3245  if (app_.getOPs().recvValidation(val, std::to_string(id())) ||
3246  cluster())
3247  {
3248  // haveMessage contains peers, which are suppressed; i.e. the peers
3249  // are the source of the message, consequently the message should
3250  // not be relayed to these peers. But the message must be counted
3251  // as part of the squelch logic.
3252  auto haveMessage =
3253  overlay_.relay(*packet, key, val->getSignerPublic());
3254  if (reduceRelayReady() && !haveMessage.empty())
3255  {
3256  overlay_.updateSlotAndSquelch(
3257  key,
3258  val->getSignerPublic(),
3259  std::move(haveMessage),
3260  protocol::mtVALIDATION);
3261  }
3262  }
3263  }
3264  catch (std::exception const& ex)
3265  {
3266  JLOG(p_journal_.trace())
3267  << "Exception processing validation: " << ex.what();
3268  charge(Resource::feeInvalidRequest);
3269  }
3270 }
3271 
3272 // Returns the set of peers that can help us get
3273 // the TX tree with the specified root hash.
3274 //
3276 getPeerWithTree(OverlayImpl& ov, uint256 const& rootHash, PeerImp const* skip)
3277 {
3279  int retScore = 0;
3280 
3281  ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
3282  if (p->hasTxSet(rootHash) && p.get() != skip)
3283  {
3284  auto score = p->getScore(true);
3285  if (!ret || (score > retScore))
3286  {
3287  ret = std::move(p);
3288  retScore = score;
3289  }
3290  }
3291  });
3292 
3293  return ret;
3294 }
3295 
3296 // Returns a random peer weighted by how likely to
3297 // have the ledger and how responsive it is.
3298 //
3301  OverlayImpl& ov,
3302  uint256 const& ledgerHash,
3303  LedgerIndex ledger,
3304  PeerImp const* skip)
3305 {
3307  int retScore = 0;
3308 
3309  ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
3310  if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
3311  {
3312  auto score = p->getScore(true);
3313  if (!ret || (score > retScore))
3314  {
3315  ret = std::move(p);
3316  retScore = score;
3317  }
3318  }
3319  });
3320 
3321  return ret;
3322 }
3323 
3324 void
3325 PeerImp::sendLedgerBase(
3326  std::shared_ptr<Ledger const> const& ledger,
3327  protocol::TMLedgerData& ledgerData)
3328 {
3329  JLOG(p_journal_.trace()) << "sendLedgerBase: Base data";
3330 
3331  Serializer s(sizeof(LedgerInfo));
3332  addRaw(ledger->info(), s);
3333  ledgerData.add_nodes()->set_nodedata(s.getDataPtr(), s.getLength());
3334 
3335  auto const& stateMap{ledger->stateMap()};
3336  if (stateMap.getHash() != beast::zero)
3337  {
3338  // Return account state root node if possible
3339  Serializer root(768);
3340 
3341  stateMap.serializeRoot(root);
3342  ledgerData.add_nodes()->set_nodedata(
3343  root.getDataPtr(), root.getLength());
3344 
3345  if (ledger->info().txHash != beast::zero)
3346  {
3347  auto const& txMap{ledger->txMap()};
3348  if (txMap.getHash() != beast::zero)
3349  {
3350  // Return TX root node if possible
3351  root.erase();
3352  txMap.serializeRoot(root);
3353  ledgerData.add_nodes()->set_nodedata(
3354  root.getDataPtr(), root.getLength());
3355  }
3356  }
3357  }
3358 
3359  auto message{
3360  std::make_shared<Message>(ledgerData, protocol::mtLEDGER_DATA)};
3361  send(message);
3362 }
3363 
3365 PeerImp::getLedger(std::shared_ptr<protocol::TMGetLedger> const& m)
3366 {
3367  JLOG(p_journal_.trace()) << "getLedger: Ledger";
3368 
3370 
3371  if (m->has_ledgerhash())
3372  {
3373  // Attempt to find ledger by hash
3374  uint256 const ledgerHash{m->ledgerhash()};
3375  ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
3376  if (!ledger)
3377  {
3378  if (m->has_ledgerseq())
3379  {
3380  // Attempt to find ledger by sequence in the shard store
3381  if (auto shards = app_.getShardStore())
3382  {
3383  if (m->ledgerseq() >= shards->earliestLedgerSeq())
3384  {
3385  ledger =
3386  shards->fetchLedger(ledgerHash, m->ledgerseq());
3387  }
3388  }
3389  }
3390 
3391  if (!ledger)
3392  {
3393  JLOG(p_journal_.trace())
3394  << "getLedger: Don't have ledger with hash " << ledgerHash;
3395 
3396  if (m->has_querytype() && !m->has_requestcookie())
3397  {
3398  // Attempt to relay the request to a peer
3399  if (auto const peer = getPeerWithLedger(
3400  overlay_,
3401  ledgerHash,
3402  m->has_ledgerseq() ? m->ledgerseq() : 0,
3403  this))
3404  {
3405  m->set_requestcookie(id());
3406  peer->send(std::make_shared<Message>(
3407  *m, protocol::mtGET_LEDGER));
3408  JLOG(p_journal_.debug())
3409  << "getLedger: Request relayed to peer";
3410  return ledger;
3411  }
3412 
3413  JLOG(p_journal_.trace())
3414  << "getLedger: Failed to find peer to relay request";
3415  }
3416  }
3417  }
3418  }
3419  else if (m->has_ledgerseq())
3420  {
3421  // Attempt to find ledger by sequence
3422  if (m->ledgerseq() < app_.getLedgerMaster().getEarliestFetch())
3423  {
3424  JLOG(p_journal_.debug())
3425  << "getLedger: Early ledger sequence request";
3426  }
3427  else
3428  {
3429  ledger = app_.getLedgerMaster().getLedgerBySeq(m->ledgerseq());
3430  if (!ledger)
3431  {
3432  JLOG(p_journal_.debug())
3433  << "getLedger: Don't have ledger with sequence "
3434  << m->ledgerseq();
3435  }
3436  }
3437  }
3438  else if (m->has_ltype() && m->ltype() == protocol::ltCLOSED)
3439  {
3440  ledger = app_.getLedgerMaster().getClosedLedger();
3441  }
3442 
3443  if (ledger)
3444  {
3445  // Validate retrieved ledger sequence
3446  auto const ledgerSeq{ledger->info().seq};
3447  if (m->has_ledgerseq())
3448  {
3449  if (ledgerSeq != m->ledgerseq())
3450  {
3451  // Do not resource charge a peer responding to a relay
3452  if (!m->has_requestcookie())
3453  charge(Resource::feeInvalidRequest);
3454 
3455  ledger.reset();
3456  JLOG(p_journal_.warn())
3457  << "getLedger: Invalid ledger sequence " << ledgerSeq;
3458  }
3459  }
3460  else if (ledgerSeq < app_.getLedgerMaster().getEarliestFetch())
3461  {
3462  ledger.reset();
3463  JLOG(p_journal_.debug())
3464  << "getLedger: Early ledger sequence request " << ledgerSeq;
3465  }
3466  }
3467  else
3468  {
3469  JLOG(p_journal_.debug()) << "getLedger: Unable to find ledger";
3470  }
3471 
3472  return ledger;
3473 }
3474 
3476 PeerImp::getTxSet(std::shared_ptr<protocol::TMGetLedger> const& m) const
3477 {
3478  JLOG(p_journal_.trace()) << "getTxSet: TX set";
3479 
3480  uint256 const txSetHash{m->ledgerhash()};
3481  std::shared_ptr<SHAMap> shaMap{
3482  app_.getInboundTransactions().getSet(txSetHash, false)};
3483  if (!shaMap)
3484  {
3485  if (m->has_querytype() && !m->has_requestcookie())
3486  {
3487  // Attempt to relay the request to a peer
3488  if (auto const peer = getPeerWithTree(overlay_, txSetHash, this))
3489  {
3490  m->set_requestcookie(id());
3491  peer->send(
3492  std::make_shared<Message>(*m, protocol::mtGET_LEDGER));
3493  JLOG(p_journal_.debug()) << "getTxSet: Request relayed";
3494  }
3495  else
3496  {
3497  JLOG(p_journal_.debug())
3498  << "getTxSet: Failed to find relay peer";
3499  }
3500  }
3501  else
3502  {
3503  JLOG(p_journal_.debug()) << "getTxSet: Failed to find TX set";
3504  }
3505  }
3506 
3507  return shaMap;
3508 }
3509 
3510 void
3511 PeerImp::processLedgerRequest(std::shared_ptr<protocol::TMGetLedger> const& m)
3512 {
3513  // Do not resource charge a peer responding to a relay
3514  if (!m->has_requestcookie())
3515  charge(Resource::feeMediumBurdenPeer);
3516 
3519  SHAMap const* map{nullptr};
3520  protocol::TMLedgerData ledgerData;
3521  bool fatLeaves{true};
3522  auto const itype{m->itype()};
3523 
3524  if (itype == protocol::liTS_CANDIDATE)
3525  {
3526  if (sharedMap = getTxSet(m); !sharedMap)
3527  return;
3528  map = sharedMap.get();
3529 
3530  // Fill out the reply
3531  ledgerData.set_ledgerseq(0);
3532  ledgerData.set_ledgerhash(m->ledgerhash());
3533  ledgerData.set_type(protocol::liTS_CANDIDATE);
3534  if (m->has_requestcookie())
3535  ledgerData.set_requestcookie(m->requestcookie());
3536 
3537  // We'll already have most transactions
3538  fatLeaves = false;
3539  }
3540  else
3541  {
3542  if (send_queue_.size() >= Tuning::dropSendQueue)
3543  {
3544  JLOG(p_journal_.debug())
3545  << "processLedgerRequest: Large send queue";
3546  return;
3547  }
3548  if (app_.getFeeTrack().isLoadedLocal() && !cluster())
3549  {
3550  JLOG(p_journal_.debug()) << "processLedgerRequest: Too busy";
3551  return;
3552  }
3553 
3554  if (ledger = getLedger(m); !ledger)
3555  return;
3556 
3557  // Fill out the reply
3558  auto const ledgerHash{ledger->info().hash};
3559  ledgerData.set_ledgerhash(ledgerHash.begin(), ledgerHash.size());
3560  ledgerData.set_ledgerseq(ledger->info().seq);
3561  ledgerData.set_type(itype);
3562  if (m->has_requestcookie())
3563  ledgerData.set_requestcookie(m->requestcookie());
3564 
3565  switch (itype)
3566  {
3567  case protocol::liBASE:
3568  sendLedgerBase(ledger, ledgerData);
3569  return;
3570 
3571  case protocol::liTX_NODE:
3572  map = &ledger->txMap();
3573  JLOG(p_journal_.trace()) << "processLedgerRequest: TX map hash "
3574  << to_string(map->getHash());
3575  break;
3576 
3577  case protocol::liAS_NODE:
3578  map = &ledger->stateMap();
3579  JLOG(p_journal_.trace())
3580  << "processLedgerRequest: Account state map hash "
3581  << to_string(map->getHash());
3582  break;
3583 
3584  default:
3585  // This case should not be possible here
3586  JLOG(p_journal_.error())
3587  << "processLedgerRequest: Invalid ledger info type";
3588  return;
3589  }
3590  }
3591 
3592  if (!map)
3593  {
3594  JLOG(p_journal_.warn()) << "processLedgerRequest: Unable to find map";
3595  return;
3596  }
3597 
3598  // Add requested node data to reply
3599  if (m->nodeids_size() > 0)
3600  {
3601  auto const queryDepth{
3602  m->has_querydepth() ? m->querydepth() : (isHighLatency() ? 2 : 1)};
3603 
3605 
3606  for (int i = 0; i < m->nodeids_size() &&
3607  ledgerData.nodes_size() < Tuning::softMaxReplyNodes;
3608  ++i)
3609  {
3610  auto const shaMapNodeId{deserializeSHAMapNodeID(m->nodeids(i))};
3611 
3612  data.clear();
3613  data.reserve(Tuning::softMaxReplyNodes);
3614 
3615  try
3616  {
3617  if (map->getNodeFat(*shaMapNodeId, data, fatLeaves, queryDepth))
3618  {
3619  JLOG(p_journal_.trace())
3620  << "processLedgerRequest: getNodeFat got "
3621  << data.size() << " nodes";
3622 
3623  for (auto const& d : data)
3624  {
3625  protocol::TMLedgerNode* node{ledgerData.add_nodes()};
3626  node->set_nodeid(d.first.getRawString());
3627  node->set_nodedata(d.second.data(), d.second.size());
3628  }
3629  }
3630  else
3631  {
3632  JLOG(p_journal_.warn())
3633  << "processLedgerRequest: getNodeFat returns false";
3634  }
3635  }
3636  catch (std::exception const& e)
3637  {
3638  std::string info;
3639  switch (itype)
3640  {
3641  case protocol::liBASE:
3642  // This case should not be possible here
3643  info = "Ledger base";
3644  break;
3645 
3646  case protocol::liTX_NODE:
3647  info = "TX node";
3648  break;
3649 
3650  case protocol::liAS_NODE:
3651  info = "AS node";
3652  break;
3653 
3654  case protocol::liTS_CANDIDATE:
3655  info = "TS candidate";
3656  break;
3657 
3658  default:
3659  info = "Invalid";
3660  break;
3661  }
3662 
3663  if (!m->has_ledgerhash())
3664  info += ", no hash specified";
3665 
3666  JLOG(p_journal_.error())
3667  << "processLedgerRequest: getNodeFat with nodeId "
3668  << *shaMapNodeId << " and ledger info type " << info
3669  << " throws exception: " << e.what();
3670  }
3671  }
3672 
3673  JLOG(p_journal_.info())
3674  << "processLedgerRequest: Got request for " << m->nodeids_size()
3675  << " nodes at depth " << queryDepth << ", return "
3676  << ledgerData.nodes_size() << " nodes";
3677  }
3678 
3679  send(std::make_shared<Message>(ledgerData, protocol::mtLEDGER_DATA));
3680 }
3681 
3682 int
3683 PeerImp::getScore(bool haveItem) const
3684 {
3685  // Random component of score, used to break ties and avoid
3686  // overloading the "best" peer
3687  static const int spRandomMax = 9999;
3688 
3689  // Score for being very likely to have the thing we are
3690  // look for; should be roughly spRandomMax
3691  static const int spHaveItem = 10000;
3692 
3693  // Score reduction for each millisecond of latency; should
3694  // be roughly spRandomMax divided by the maximum reasonable
3695  // latency
3696  static const int spLatency = 30;
3697 
3698  // Penalty for unknown latency; should be roughly spRandomMax
3699  static const int spNoLatency = 8000;
3700 
3701  int score = rand_int(spRandomMax);
3702 
3703  if (haveItem)
3704  score += spHaveItem;
3705 
3707  {
3708  std::lock_guard sl(recentLock_);
3709  latency = latency_;
3710  }
3711 
3712  if (latency)
3713  score -= latency->count() * spLatency;
3714  else
3715  score -= spNoLatency;
3716 
3717  return score;
3718 }
3719 
3720 bool
3721 PeerImp::isHighLatency() const
3722 {
3723  std::lock_guard sl(recentLock_);
3724  return latency_ >= peerHighLatency;
3725 }
3726 
3727 bool
3728 PeerImp::reduceRelayReady()
3729 {
3730  if (!reduceRelayReady_)
3731  reduceRelayReady_ =
3732  reduce_relay::epoch<std::chrono::minutes>(UptimeClock::now()) >
3733  reduce_relay::WAIT_ON_BOOTUP;
3734  return vpReduceRelayEnabled_ && reduceRelayReady_;
3735 }
3736 
3737 void
3738 PeerImp::Metrics::add_message(std::uint64_t bytes)
3739 {
3740  using namespace std::chrono_literals;
3741  std::unique_lock lock{mutex_};
3742 
3743  totalBytes_ += bytes;
3744  accumBytes_ += bytes;
3745  auto const timeElapsed = clock_type::now() - intervalStart_;
3746  auto const timeElapsedInSecs =
3747  std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
3748 
3749  if (timeElapsedInSecs >= 1s)
3750  {
3751  auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
3752  rollingAvg_.push_back(avgBytes);
3753 
3754  auto const totalBytes =
3755  std::accumulate(rollingAvg_.begin(), rollingAvg_.end(), 0ull);
3756  rollingAvgBytes_ = totalBytes / rollingAvg_.size();
3757 
3758  intervalStart_ = clock_type::now();
3759  accumBytes_ = 0;
3760  }
3761 }
3762 
3764 PeerImp::Metrics::average_bytes() const
3765 {
3766  std::shared_lock lock{mutex_};
3767  return rollingAvgBytes_;
3768 }
3769 
3771 PeerImp::Metrics::total_bytes() const
3772 {
3773  std::shared_lock lock{mutex_};
3774  return totalBytes_;
3775 }
3776 
3777 } // namespace ripple
ripple::PublicKey::data
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:83
ripple::PeerImp::latency_
std::optional< std::chrono::milliseconds > latency_
Definition: PeerImp.h:114
ripple::PeerImp::ledgerRange
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
Definition: PeerImp.cpp:571
ripple::PeerImp::uptime
clock_type::duration uptime() const
Definition: PeerImp.h:354
ripple::Resource::feeInvalidRequest
const Charge feeInvalidRequest
Schedule of fees charged for imposing load on the server.
ripple::Application
Definition: Application.h:116
ripple::ClusterNode
Definition: ClusterNode.h:30
ripple::jtTRANSACTION
@ jtTRANSACTION
Definition: Job.h:63
ripple::PeerImp::inbound_
const bool inbound_
Definition: PeerImp.h:91
ripple::TrafficCount::categorize
static category categorize(::google::protobuf::Message const &message, int type, bool inbound)
Given a protocol message, determine which traffic category it belongs to.
Definition: TrafficCount.cpp:25
sstream
ripple::PeerImp::recentLock_
std::mutex recentLock_
Definition: PeerImp.h:149
ripple::HashRouter::addSuppressionPeerWithStatus
std::pair< bool, std::optional< Stopwatch::time_point > > addSuppressionPeerWithStatus(uint256 const &key, PeerShortID peer)
Add a suppression peer and get message's relay status.
Definition: HashRouter.cpp:57
ripple::RCLCxPeerPos
A peer's signed, proposed position for use in RCLConsensus.
Definition: RCLCxPeerPos.h:43
std::weak_ptr::lock
T lock(T... args)
std::for_each
T for_each(T... args)
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:241
ripple::Application::cluster
virtual Cluster & cluster()=0
ripple::PeerImp::socket_
socket_type & socket_
Definition: PeerImp.h:79
std::bind
T bind(T... args)
ripple::PeerImp::trackingTime_
clock_type::time_point trackingTime_
Definition: PeerImp.h:97
ripple::ShardState::complete
@ complete
std::string
STL class.
ripple::Resource::feeMediumBurdenPeer
const Charge feeMediumBurdenPeer
std::shared_ptr
STL class.
ripple::Resource::Consumer::disconnect
bool disconnect(beast::Journal const &j)
Returns true if the consumer should be disconnected.
Definition: Consumer.cpp:117
ripple::PeerImp::addTxQueue
void addTxQueue(uint256 const &hash) override
Add transaction's hash to the transactions' hashes queue.
Definition: PeerImp.cpp:342
ripple::PeerImp::onMessage
void onMessage(std::shared_ptr< protocol::TMManifests > const &m)
Definition: PeerImp.cpp:1048
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: app/misc/impl/Manifest.cpp:303
ripple::jtMANIFEST
@ jtMANIFEST
Definition: Job.h:56
std::exception
STL class.
ripple::PeerImp::hasTxSet
bool hasTxSet(uint256 const &hash) const override
Definition: PeerImp.cpp:580
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:303
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:308
ripple::PeerImp::strand_
boost::asio::strand< boost::asio::executor > strand_
Definition: PeerImp.h:81
ripple::sfLedgerSequence
const SF_UINT32 sfLedgerSequence
ripple::PeerImp::recentLedgers_
boost::circular_buffer< uint256 > recentLedgers_
Definition: PeerImp.h:111
ripple::PeerImp::ledgerReplayEnabled_
bool ledgerReplayEnabled_
Definition: PeerImp.h:181
ripple::deserializeSHAMapNodeID
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
Definition: SHAMapNodeID.cpp:101
ripple::Resource::Gossip
Data format for exchanging consumption information across peers.
Definition: Gossip.h:29
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::PeerImp::~PeerImp
virtual ~PeerImp()
Definition: PeerImp.cpp:165
ripple::relayLimit
static constexpr std::uint32_t relayLimit
Definition: ripple/overlay/Peer.h:36
beast::IP::Endpoint::to_string
std::string to_string() const
Returns a string representing the endpoint.
Definition: IPEndpoint.cpp:57
ripple::closeReasonToString
std::string closeReasonToString(protocol::TMCloseReason reason)
Definition: PeerImp.cpp:69
std::pair
ripple::jtMISSING_TXN
@ jtMISSING_TXN
Definition: Job.h:64
std::vector::reserve
T reserve(T... args)
ripple::OverlayImpl::updateSlotAndSquelch
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, std::set< Peer::id_t > &&peers, protocol::MessageType type)
Updates message count for validator/peer.
Definition: OverlayImpl.cpp:1477
ripple::HashRouter::shouldProcess
bool shouldProcess(uint256 const &key, PeerShortID peer, int &flags, std::chrono::seconds tx_interval)
Definition: HashRouter.cpp:78
ripple::PeerImp::handleTransaction
void handleTransaction(std::shared_ptr< protocol::TMTransaction > const &m, bool eraseTxQueue)
Called from onMessage(TMTransaction(s)).
Definition: PeerImp.cpp:1518
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:213
ripple::OverlayImpl::endOfPeerChain
void endOfPeerChain(std::uint32_t id)
Called when the reply from the last peer in a peer chain is received.
Definition: OverlayImpl.cpp:767
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::PeerImp::doProtocolStart
void doProtocolStart()
Definition: PeerImp.cpp:827
std::vector
STL class.
std::find
T find(T... args)
std::string::size
T size(T... args)
ripple::PeerImp::recentTxSets_
boost::circular_buffer< uint256 > recentTxSets_
Definition: PeerImp.h:112
ripple::PublicKey::empty
bool empty() const noexcept
Definition: PublicKey.h:119
ripple::PeerImp::sendTxQueue
void sendTxQueue() override
Send aggregated transactions' hashes.
Definition: PeerImp.cpp:323
ripple::make_protocol
constexpr ProtocolVersion make_protocol(std::uint16_t major, std::uint16_t minor)
Definition: ProtocolVersion.h:40
ripple::PeerImp::txReduceRelayEnabled
bool txReduceRelayEnabled() const override
Definition: PeerImp.h:431
ripple::FEATURE_LEDGER_REPLAY
static constexpr char FEATURE_LEDGER_REPLAY[]
Definition: Handshake.h:148
std::chrono::milliseconds
ripple::PeerImp::setTimer
void setTimer()
Definition: PeerImp.cpp:697
ripple::ProtocolFeature::LedgerReplay
@ LedgerReplay
ripple::OverlayImpl::incPeerDisconnectCharges
void incPeerDisconnectCharges() override
Definition: OverlayImpl.h:378
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
beast::IP::Endpoint::address
Address const & address() const
Returns the address portion of this endpoint.
Definition: IPEndpoint.h:76
ripple::PeerImp::getVersion
std::string getVersion() const
Return the version of rippled that the peer is running, if reported.
Definition: PeerImp.cpp:400
std::set::emplace
T emplace(T... args)
std::stringstream
STL class.
beast::Journal::warn
Stream warn() const
Definition: Journal.h:326
std::shared_ptr::get
T get(T... args)
std::lock_guard
STL class.
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::PeerImp::close
void close()
Definition: PeerImp.cpp:608
ripple::PeerImp::charge
void charge(Resource::Charge const &fee) override
Adjust this peer's load balance based on the type of load imposed.
Definition: PeerImp.cpp:371
ripple::PeerImp::onMessageUnknown
void onMessageUnknown(std::uint16_t type)
Definition: PeerImp.cpp:999
ripple::Cluster::member
std::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
Definition: Cluster.cpp:39
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
ripple::stopwatch
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:120
std::setfill
T setfill(T... args)
ripple::PeerImp::journal_
const beast::Journal journal_
Definition: PeerImp.h:76
ripple::PeerImp::send
void send(std::shared_ptr< Message > const &m) override
Definition: PeerImp.cpp:269
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::ProtocolFeature
ProtocolFeature
Definition: ripple/overlay/Peer.h:38
ripple::PeerImp::onTimer
void onTimer(boost::system::error_code const &ec)
Definition: PeerImp.cpp:732
ripple::ShardState
ShardState
Shard states.
Definition: nodestore/Types.h:61
ripple::Cluster::update
bool update(PublicKey const &identity, std::string name, std::uint32_t loadFee=0, NetClock::time_point reportTime=NetClock::time_point{})
Store information about the state of a cluster node.
Definition: Cluster.cpp:58
ripple::PeerImp::lastPingTime_
clock_type::time_point lastPingTime_
Definition: PeerImp.h:116
ripple::OverlayImpl::incJqTransOverflow
void incJqTransOverflow() override
Increment and retrieve counter for transaction job queue overflows.
Definition: OverlayImpl.h:354
ripple::PeerImp
Definition: PeerImp.h:52
ripple::ProtocolFeature::StartProtocol
@ StartProtocol
ripple::Config::MAX_TRANSACTIONS
int MAX_TRANSACTIONS
Definition: Config.h:237
ripple::PeerImp::previousLedgerHash_
uint256 previousLedgerHash_
Definition: PeerImp.h:109
ripple::FEATURE_VPRR
static constexpr char FEATURE_VPRR[]
Definition: Handshake.h:144
ripple::TimeKeeper::closeTime
time_point closeTime() const
Returns the predicted close time, in network time.
Definition: TimeKeeper.h:76
std::optional::reset
T reset(T... args)
ripple::PeerImp::txQueue_
hash_set< uint256 > txQueue_
Definition: PeerImp.h:175
ripple::base_uint::data
pointer data()
Definition: base_uint.h:122
algorithm
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::PeerImp::name_
std::string name_
Definition: PeerImp.h:101
ripple::PeerFinder::Manager::on_endpoints
virtual void on_endpoints(std::shared_ptr< Slot > const &slot, Endpoints const &endpoints)=0
Called when mtENDPOINTS is received.
ripple::forceValidity
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition: apply.cpp:89
ripple::Application::getInboundLedgers
virtual InboundLedgers & getInboundLedgers()=0
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::base_uint< 256 >::size
constexpr static std::size_t size()
Definition: base_uint.h:519
ripple::getPeerWithLedger
static std::shared_ptr< PeerImp > getPeerWithLedger(OverlayImpl &ov, uint256 const &ledgerHash, LedgerIndex ledger, PeerImp const *skip)
Definition: PeerImp.cpp:3300
ripple::PeerImp::publicKey_
const PublicKey publicKey_
Definition: PeerImp.h:100
ripple::protocolMessageName
std::string protocolMessageName(int type)
Returns the name of a protocol message given its type.
Definition: ProtocolMessage.h:61
ripple::Serializer::data
void const * data() const noexcept
Definition: Serializer.h:76
ripple::PeerImp::read_buffer_
boost::beast::multi_buffer read_buffer_
Definition: PeerImp.h:154
ripple::PeerImp::error_code
boost::system::error_code error_code
Definition: PeerImp.h:62
ripple::JobQueue::getJobCount
int getJobCount(JobType t) const
Jobs waiting at this priority.
Definition: JobQueue.cpp:128
ripple::FEATURE_TXRR
static constexpr char FEATURE_TXRR[]
Definition: Handshake.h:146
std::tie
T tie(T... args)
ripple::PeerImp::remote_address_
const beast::IP::Endpoint remote_address_
Definition: PeerImp.h:86
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::jtTXN_DATA
@ jtTXN_DATA
Definition: Job.h:70
ripple::PeerFinder::Manager::on_closed
virtual void on_closed(std::shared_ptr< Slot > const &slot)=0
Called when the slot is closed.
ripple::OverlayImpl::peerFinder
PeerFinder::Manager & peerFinder()
Definition: OverlayImpl.h:164
ripple::getPeerWithTree
static std::shared_ptr< PeerImp > getPeerWithTree(OverlayImpl &ov, uint256 const &rootHash, PeerImp const *skip)
Definition: PeerImp.cpp:3276
ripple::base_uint< 256 >
ripple::INCLUDED
@ INCLUDED
Definition: Transaction.h:49
ripple::LoadFeeTrack::isLoadedLocal
bool isLoadedLocal() const
Definition: LoadFeeTrack.h:126
ripple::PeerImp::addLedger
void addLedger(uint256 const &hash, std::lock_guard< std::mutex > const &lockedRecentLock)
Definition: PeerImp.cpp:3003
ripple::Config::RELAY_UNTRUSTED_PROPOSALS
int RELAY_UNTRUSTED_PROPOSALS
Definition: Config.h:180
ripple::Resource::feeInvalidSignature
const Charge feeInvalidSignature
ripple::OverlayImpl::onManifests
void onManifests(std::shared_ptr< protocol::TMManifests > const &m, std::shared_ptr< PeerImp > const &from)
Definition: OverlayImpl.cpp:618
std::enable_shared_from_this< PeerImp >::shared_from_this
T shared_from_this(T... args)
ripple::PeerImp::onStartProtocol
void onStartProtocol()
Definition: PeerImp.cpp:2938
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::NetworkOPs::isNeedNetworkLedger
virtual bool isNeedNetworkLedger()=0
ripple::Resource::drop
@ drop
Definition: Disposition.h:37
ripple::checkValidity
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Definition: apply.cpp:37
ripple::jtPROPOSAL_t
@ jtPROPOSAL_t
Definition: Job.h:75
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:532
ripple::OverlayImpl::resourceManager
Resource::Manager & resourceManager()
Definition: OverlayImpl.h:170
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::LedgerReplayMsgHandler::processProofPathResponse
bool processProofPathResponse(std::shared_ptr< protocol::TMProofPathResponse > const &msg)
Process TMProofPathResponse.
Definition: LedgerReplayMsgHandler.cpp:106
ripple::PeerImp::gracefulClose
void gracefulClose()
Definition: PeerImp.cpp:681
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
std::atomic::load
T load(T... args)
ripple::Resource::feeBadData
const Charge feeBadData
ripple::PublicKey::size
std::size_t size() const noexcept
Definition: PublicKey.h:89
ripple::Serializer::getDataPtr
const void * getDataPtr() const
Definition: Serializer.h:190
ripple::Resource::Manager::importConsumers
virtual void importConsumers(std::string const &origin, Gossip const &gossip)=0
Import packaged consumer information.
chrono
ripple::PeerImp::closedLedgerHash_
uint256 closedLedgerHash_
Definition: PeerImp.h:108
ripple::PeerImp::detaching_
bool detaching_
Definition: PeerImp.h:98
ripple::PeerImp::onMessageEnd
void onMessageEnd(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m)
Definition: PeerImp.cpp:1039
ripple::Application::config
virtual Config & config()=0
ripple::PeerImp::shardInfos_
hash_map< PublicKey, NodeStore::ShardInfo > shardInfos_
Definition: PeerImp.h:167
ripple::isCurrent
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
Definition: Validations.h:148
beast::Journal::active
bool active(Severity level) const
Returns true if any message would be logged at this severity level.
Definition: Journal.h:300
ripple::PeerImp::stream_
stream_type & stream_
Definition: PeerImp.h:80
ripple::PeerImp::onWriteMessage
void onWriteMessage(error_code ec, std::size_t bytes_transferred)
Definition: PeerImp.cpp:936
std::unique_lock
STL class.
ripple::SHAMap
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
Definition: SHAMap.h:95
ripple::InfoSub::Source::pubPeerStatus
virtual void pubPeerStatus(std::function< Json::Value(void)> const &)=0
ripple::Application::nodeIdentity
virtual std::pair< PublicKey, SecretKey > const & nodeIdentity()=0
ripple::Tuning::hardMaxReplyNodes
@ hardMaxReplyNodes
The hard cap on the number of ledger entries in a single reply.
Definition: overlay/impl/Tuning.h:42
ripple::jtVALIDATION_t
@ jtVALIDATION_t
Definition: Job.h:72
ripple::reduce_relay::IDLED
static constexpr auto IDLED
Definition: ReduceRelayCommon.h:43
ripple::PeerImp::hasRange
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
Definition: PeerImp.cpp:598
ripple::Resource::feeUnwantedData
const Charge feeUnwantedData
ripple::Serializer::addRaw
int addRaw(Blob const &vector)
Definition: Serializer.cpp:100
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::Resource::Gossip::items
std::vector< Item > items
Definition: Gossip.h:42
ripple::PeerImp::cycleStatus
void cycleStatus() override
Definition: PeerImp.cpp:588
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
ripple::PeerImp::app_
Application & app_
Definition: PeerImp.h:72
ripple::PeerImp::crawl
bool crawl() const
Returns true if this connection will publicly share its IP address.
Definition: PeerImp.cpp:385
ripple::PeerImp::minLedger_
LedgerIndex minLedger_
Definition: PeerImp.h:106
ripple::FEATURE_COMPR
static constexpr char FEATURE_COMPR[]
Definition: Handshake.h:142
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
ripple::PeerImp::ledgerReplayMsgHandler_
LedgerReplayMsgHandler ledgerReplayMsgHandler_
Definition: PeerImp.h:182
ripple::base64_decode
std::string base64_decode(std::string const &data)
Definition: base64.cpp:245
beast::Journal::error
Stream error() const
Definition: Journal.h:332
beast::Journal::info
Stream info() const
Definition: Journal.h:320
std::chrono::time_point
ripple::ShardState::finalized
@ finalized
ripple::PeerImp::hasLedger
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
Definition: PeerImp.cpp:545
ripple::PeerImp::Tracking::unknown
@ unknown
ripple::Resource::Consumer::balance
int balance()
Returns the credit balance representing consumption.
Definition: Consumer.cpp:129
ripple::HashPrefix::proposal
@ proposal
proposal for signing
ripple::PeerImp::headers_
boost::beast::http::fields const & headers_
Definition: PeerImp.h:157
std::accumulate
T accumulate(T... args)
ripple::SerialIter
Definition: Serializer.h:311
ripple::PeerImp::metrics_
struct ripple::PeerImp::@13 metrics_
ripple::peerFeatureEnabled
bool peerFeatureEnabled(headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
Definition: Handshake.h:199
ripple::PeerImp::reduceRelayReady
bool reduceRelayReady()
Definition: PeerImp.cpp:3728
std::uint32_t
ripple::PeerImp::fail
void fail(protocol::TMCloseReason reason)
Definition: PeerImp.cpp:630
ripple::PeerImp::send_queue_
std::queue< std::shared_ptr< Message > > send_queue_
Definition: PeerImp.h:158
ripple::PeerImp::slot_
const std::shared_ptr< PeerFinder::Slot > slot_
Definition: PeerImp.h:153
ripple::Overlay::foreach
void foreach(Function f) const
Visit every active peer.
Definition: Overlay.h:198
ripple::PeerImp::load_event_
std::unique_ptr< LoadEvent > load_event_
Definition: PeerImp.h:161
ripple::ShardState::finalizing
@ finalizing
std::map
STL class.
ripple::PeerImp::protocol_
ProtocolVersion protocol_
Definition: PeerImp.h:94
ripple::Application::getValidationPublicKey
virtual PublicKey const & getValidationPublicKey() const =0
ripple::TimeKeeper::now
time_point now() const override
Returns the current time, using the server's clock.
Definition: TimeKeeper.h:64
ripple::Cluster::size
std::size_t size() const
The number of nodes in the cluster list.
Definition: Cluster.cpp:50
std::nth_element
T nth_element(T... args)
memory
ripple::PeerImp::waitable_timer
boost::asio::basic_waitable_timer< std::chrono::steady_clock > waitable_timer
Definition: PeerImp.h:69
ripple::jtPEER
@ jtPEER
Definition: Job.h:81
ripple::NodeStore::ShardInfo
Definition: ShardInfo.h:32
ripple::PeerImp::onShutdown
void onShutdown(error_code ec)
Definition: PeerImp.cpp:793
ripple::PeerImp::closeOnWriteComplete_
bool closeOnWriteComplete_
Definition: PeerImp.h:184
ripple::proposalUniqueId
uint256 proposalUniqueId(uint256 const &proposeHash, uint256 const &previousLedger, std::uint32_t proposeSeq, NetClock::time_point closeTime, Slice const &publicKey, Slice const &signature)
Calculate a unique identifier for a signed proposal.
Definition: RCLCxPeerPos.cpp:66
ripple::PeerImp::name
std::string name() const
Definition: PeerImp.cpp:810
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::LedgerHeader
Information about the notional ledger backing the view.
Definition: LedgerHeader.h:33
ripple::KeyType::secp256k1
@ secp256k1
ripple::RCLCxPeerPos::publicKey
PublicKey const & publicKey() const
Public key of peer that sent the proposal.
Definition: RCLCxPeerPos.h:78
std::weak_ptr
STL class.
ripple::PeerImp::timer_
waitable_timer timer_
Definition: PeerImp.h:82
std::min
T min(T... args)
ripple::Serializer
Definition: Serializer.h:40
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:274
ripple::Resource::Gossip::Item
Describes a single consumer.
Definition: Gossip.h:34
ripple::OverlayImpl::deletePeer
void deletePeer(Peer::id_t id)
Called when the peer is deleted.
Definition: OverlayImpl.cpp:1510
ripple::jtREQUESTED_TXN
@ jtREQUESTED_TXN
Definition: Job.h:65
ripple::PeerImp::Tracking::diverged
@ diverged
ripple::jtPACK
@ jtPACK
Definition: Job.h:43
ripple::PeerImp::gracefulClose_
bool gracefulClose_
Definition: PeerImp.h:159
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::InboundLedgers::gotLedgerData
virtual bool gotLedgerData(LedgerHash const &ledgerHash, std::shared_ptr< Peer >, std::shared_ptr< protocol::TMLedgerData >)=0
ripple::Application::getNodeStore
virtual NodeStore::Database & getNodeStore()=0
ripple::Application::validatorManifests
virtual ManifestCache & validatorManifests()=0
ripple::addRaw
void addRaw(LedgerHeader const &info, Serializer &s, bool includeHash)
Definition: protocol/impl/LedgerHeader.cpp:25
ripple::OverlayImpl::getManifestsMessage
std::shared_ptr< Message > getManifestsMessage()
Definition: OverlayImpl.cpp:1269
ripple::Serializer::size
std::size_t size() const noexcept
Definition: Serializer.h:70
ripple::send_if_not
send_if_not_pred< Predicate > send_if_not(std::shared_ptr< Message > const &m, Predicate const &f)
Helper function to aid in type deduction.
Definition: predicates.h:107
ripple::ShardState::acquire
@ acquire
protocol
Definition: ValidatorList.h:38
ripple::jtVALIDATION_ut
@ jtVALIDATION_ut
Definition: Job.h:55
ripple::INVALID
@ INVALID
Definition: Transaction.h:48
ripple::reduce_relay::MAX_TX_QUEUE_SIZE
static constexpr std::size_t MAX_TX_QUEUE_SIZE
Definition: ReduceRelayCommon.h:59
ripple::ProtocolFeature::ValidatorList2Propagation
@ ValidatorList2Propagation
ripple::OverlayImpl::remove
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
Definition: OverlayImpl.cpp:455
ripple::PeerImp::squelch_
reduce_relay::Squelch< UptimeClock > squelch_
Definition: PeerImp.h:119
ripple::Config::TX_REDUCE_RELAY_METRICS
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:277
ripple::PeerImp::lastPingSeq_
std::optional< std::uint32_t > lastPingSeq_
Definition: PeerImp.h:115
ripple::base_uint::zero
void zero()
Definition: base_uint.h:542
ripple::NodeStore::Database::seqToShardIndex
std::uint32_t seqToShardIndex(std::uint32_t ledgerSeq) const noexcept
Calculates the shard index for a given ledger sequence.
Definition: Database.h:283
std
STL namespace.
beast::severities::kWarning
@ kWarning
Definition: Journal.h:37
ripple::NodeStore::Database::earliestShardIndex
std::uint32_t earliestShardIndex() const noexcept
Definition: Database.h:246
std::set::insert
T insert(T... args)
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:216
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
ripple::OverlayImpl::onPeerDeactivate
void onPeerDeactivate(Peer::id_t id)
Definition: OverlayImpl.cpp:611
ripple::Tuning::readBufferBytes
constexpr std::size_t readBufferBytes
Size of buffer used to read from the socket.
Definition: overlay/impl/Tuning.h:65
ripple::Resource::Gossip::Item::address
beast::IP::Endpoint address
Definition: Gossip.h:39
ripple::LedgerMaster::getCurrentLedgerIndex
LedgerIndex getCurrentLedgerIndex()
Definition: LedgerMaster.cpp:207
ripple::Resource::Consumer
An endpoint that consumes resources.
Definition: Consumer.h:34
ripple::Resource::Charge
A consumption charge.
Definition: Charge.h:30
ripple::Resource::Gossip::Item::balance
int balance
Definition: Gossip.h:38
ripple::PeerImp::maxLedger_
LedgerIndex maxLedger_
Definition: PeerImp.h:107
ripple::PeerImp::run
virtual void run()
Definition: PeerImp.cpp:188
ripple::Tuning::targetSendQueue
@ targetSendQueue
How many messages we consider reasonable sustained on a send queue.
Definition: overlay/impl/Tuning.h:52
ripple::LoadFeeTrack::setClusterFee
void setClusterFee(std::uint32_t fee)
Definition: LoadFeeTrack.h:113
ripple::PeerImp::checkTracking
void checkTracking(std::uint32_t validationSeq)
Check if the peer is tracking.
Definition: PeerImp.cpp:2189
ripple::PeerImp::large_sendq_
int large_sendq_
Definition: PeerImp.h:160
ripple::PeerImp::domain
std::string domain() const
Definition: PeerImp.cpp:817
std::string::empty
T empty(T... args)
ripple::Resource::feeLightPeer
const Charge feeLightPeer
ripple::jtREPLAY_REQ
@ jtREPLAY_REQ
Definition: Job.h:59
ripple::jtPROPOSAL_ut
@ jtPROPOSAL_ut
Definition: Job.h:61
ripple::TokenType::NodePublic
@ NodePublic
ripple::PeerImp::last_status_
protocol::TMStatusChange last_status_
Definition: PeerImp.h:150
ripple::RCLCxPeerPos::suppressionID
uint256 const & suppressionID() const
Unique id used by hash router to suppress duplicates.
Definition: RCLCxPeerPos.h:85
ripple::PeerImp::supportsFeature
bool supportsFeature(ProtocolFeature f) const override
Definition: PeerImp.cpp:526
ripple::OverlayImpl::findPeerByPublicKey
std::shared_ptr< Peer > findPeerByPublicKey(PublicKey const &pubKey) override
Returns the peer with the matching public key, or null.
Definition: OverlayImpl.cpp:1202
std::optional
mutex
ripple::PeerImp::getPeerShardInfos
const hash_map< PublicKey, NodeStore::ShardInfo > getPeerShardInfos() const
Definition: PeerImp.cpp:674
ripple::PeerImp::onMessageBegin
void onMessageBegin(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m, std::size_t size, std::size_t uncompressed_size, bool isCompressed)
Definition: PeerImp.cpp:1005
std::stringstream::str
T str(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:314
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::PeerImp::json
Json::Value json() override
Definition: PeerImp.cpp:408
ripple::Cluster::for_each
void for_each(std::function< void(ClusterNode const &)> func) const
Invokes the callback once for every cluster node.
Definition: Cluster.cpp:84
ripple::PeerImp::compressionEnabled_
Compressed compressionEnabled_
Definition: PeerImp.h:170
ripple::Tuning::sendqIntervals
@ sendqIntervals
How many timer intervals a sendq has to stay large before we disconnect.
Definition: overlay/impl/Tuning.h:46
ripple::ProtocolFeature::ValidatorListPropagation
@ ValidatorListPropagation
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:38
ripple::OverlayImpl::incPeerDisconnect
void incPeerDisconnect() override
Increment and retrieve counters for total peer disconnects, and disconnects we initiate for excessive...
Definition: OverlayImpl.h:366
ripple::OverlayImpl::addTxMetrics
void addTxMetrics(Args... args)
Add tx reduce-relay metrics.
Definition: OverlayImpl.h:447
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
std::set::end
T end(T... args)
ripple::PeerFinder::Manager::on_failure
virtual void on_failure(std::shared_ptr< Slot > const &slot)=0
Called when an outbound connection is deemed to have failed.
ripple::PeerImp::makePrefix
static std::string makePrefix(id_t id)
Definition: PeerImp.cpp:724
ripple::PeerImp::usage_
Resource::Consumer usage_
Definition: PeerImp.h:151
std::setw
T setw(T... args)
ripple::NodeStore::Database::earliestLedgerSeq
std::uint32_t earliestLedgerSeq() const noexcept
Definition: Database.h:238
numeric
ripple::OverlayImpl
Definition: OverlayImpl.h:58
std::max
T max(T... args)
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
beast::IP::Endpoint::at_port
Endpoint at_port(Port port) const
Returns a new Endpoint with a different port.
Definition: IPEndpoint.h:69
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:1367
ripple::OverlayImpl::findPeerByShortID
std::shared_ptr< Peer > findPeerByShortID(Peer::id_t const &id) const override
Returns the peer with the matching short id, or null.
Definition: OverlayImpl.cpp:1190
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:200
ripple::OverlayImpl::reportTraffic
void reportTraffic(TrafficCount::category cat, bool isInbound, int bytes)
Definition: OverlayImpl.cpp:671
ripple::sfLastLedgerSequence
const SF_UINT32 sfLastLedgerSequence
ripple::JobQueue::makeLoadEvent
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
Definition: JobQueue.cpp:165
ripple::PeerImp::shardInfoMutex_
std::mutex shardInfoMutex_
Definition: PeerImp.h:168
ripple::Resource::Consumer::charge
Disposition charge(Charge const &fee)
Apply a load charge to the consumer.
Definition: Consumer.cpp:99
ripple::PeerImp::overlay_
OverlayImpl & overlay_
Definition: PeerImp.h:90
ripple::http_request_type
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition: Handshake.h:47
std::unique_ptr< stream_type >
ripple::Tuning::sendQueueLogFreq
@ sendQueueLogFreq
How often to log send queue size.
Definition: overlay/impl/Tuning.h:55
ripple::PeerImp::tracking_
std::atomic< Tracking > tracking_
Definition: PeerImp.h:96
ripple::PeerImp::nameMutex_
boost::shared_mutex nameMutex_
Definition: PeerImp.h:102
ripple::PeerImp::cancelTimer
void cancelTimer()
Definition: PeerImp.cpp:715
ripple::invokeProtocolMessage
std::pair< std::size_t, boost::system::error_code > invokeProtocolMessage(Buffers const &buffers, Handler &handler, std::size_t &hint)
Calls the handler for up to one protocol message in the passed buffers.
Definition: ProtocolMessage.h:346
std::unordered_map
STL class.
ripple::PeerImp::fee_
Resource::Charge fee_
Definition: PeerImp.h:152
ripple::stringIsUint256Sized
static bool stringIsUint256Sized(std::string const &pBuffStr)
Definition: PeerImp.cpp:182
beast::IP::Endpoint::from_string_checked
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:35
std::set
STL class.
ripple::PeerImp::stop
void stop() override
Definition: PeerImp.cpp:243
ripple::Tuning::maxQueryDepth
@ maxQueryDepth
The maximum number of levels to search.
Definition: overlay/impl/Tuning.h:61
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::PeerImp::removeTxQueue
void removeTxQueue(uint256 const &hash) override
Remove transaction's hash from the transactions' hashes queue.
Definition: PeerImp.cpp:359
ripple::PeerImp::Tracking::converged
@ converged
ripple::PeerImp::id_
const id_t id_
Definition: PeerImp.h:73
ripple::OverlayImpl::for_each
void for_each(UnaryFunc &&f) const
Definition: OverlayImpl.h:281
std::ref
T ref(T... args)
ripple::RCLCxPeerPos::checkSign
bool checkSign() const
Verify the signing hash of the proposal.
Definition: RCLCxPeerPos.cpp:48
ripple::LedgerReplayMsgHandler::processReplayDeltaResponse
bool processReplayDeltaResponse(std::shared_ptr< protocol::TMReplayDeltaResponse > const &msg)
Process TMReplayDeltaResponse.
Definition: LedgerReplayMsgHandler.cpp:221
std::exception::what
T what(T... args)
std::shared_lock
STL class.
ripple::PeerImp::cluster
bool cluster() const override
Returns true if this connection is a member of the cluster.
Definition: PeerImp.cpp:394
ripple::ShardState::queued
@ queued
ripple::HashPrefix::shardInfo
@ shardInfo
shard info for signing
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::PeerImp::p_journal_
const beast::Journal p_journal_
Definition: PeerImp.h:77
ripple::Config::MAX_UNKNOWN_TIME
std::chrono::seconds MAX_UNKNOWN_TIME
Definition: Config.h:293
ripple::Peer
Represents a peer connection in the overlay.
Definition: ripple/overlay/Peer.h:46
ripple::Config::MAX_DIVERGED_TIME
std::chrono::seconds MAX_DIVERGED_TIME
Definition: Config.h:296
ripple::jtLEDGER_REQ
@ jtLEDGER_REQ
Definition: Job.h:60
ripple::PeerImp::onReadMessage
void onReadMessage(error_code ec, std::size_t bytes_transferred)
Definition: PeerImp.cpp:880
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:624
ripple::ConsensusProposal< NodeID, uint256, uint256 >
std::chrono::steady_clock::now
T now(T... args)