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