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