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