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/misc/HashRouter.h>
25 #include <ripple/app/misc/LoadFeeTrack.h>
26 #include <ripple/app/misc/NetworkOPs.h>
27 #include <ripple/app/misc/Transaction.h>
28 #include <ripple/app/misc/ValidatorList.h>
29 #include <ripple/app/tx/apply.h>
30 #include <ripple/basics/UptimeClock.h>
31 #include <ripple/basics/base64.h>
32 #include <ripple/basics/random.h>
33 #include <ripple/basics/safe_cast.h>
34 #include <ripple/beast/core/LexicalCast.h>
35 #include <ripple/beast/core/SemanticVersion.h>
36 #include <ripple/nodestore/DatabaseShard.h>
37 #include <ripple/overlay/Cluster.h>
38 #include <ripple/overlay/impl/PeerImp.h>
39 #include <ripple/overlay/impl/Tuning.h>
40 #include <ripple/overlay/predicates.h>
41 #include <ripple/protocol/digest.h>
42 
43 #include <boost/algorithm/clamp.hpp>
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 <numeric>
51 #include <sstream>
52 
53 using namespace std::chrono_literals;
54 
55 namespace ripple {
56 
57 PeerImp::PeerImp(
58  Application& app,
59  id_t id,
61  http_request_type&& request,
62  PublicKey const& publicKey,
63  ProtocolVersion protocol,
64  Resource::Consumer consumer,
65  std::unique_ptr<stream_type>&& stream_ptr,
66  OverlayImpl& overlay)
67  : Child(overlay)
68  , app_(app)
69  , id_(id)
70  , sink_(app_.journal("Peer"), makePrefix(id))
71  , p_sink_(app_.journal("Protocol"), makePrefix(id))
72  , journal_(sink_)
73  , p_journal_(p_sink_)
74  , stream_ptr_(std::move(stream_ptr))
75  , socket_(stream_ptr_->next_layer().socket())
76  , stream_(*stream_ptr_)
77  , strand_(socket_.get_executor())
78  , timer_(waitable_timer{socket_.get_executor()})
79  , remote_address_(slot->remote_endpoint())
80  , overlay_(overlay)
81  , m_inbound(true)
82  , protocol_(protocol)
83  , state_(State::active)
84  , sanity_(Sanity::unknown)
85  , insaneTime_(clock_type::now())
86  , publicKey_(publicKey)
87  , creationTime_(clock_type::now())
88  , usage_(consumer)
90  , slot_(slot)
91  , request_(std::move(request))
92  , headers_(request_)
93  , compressionEnabled_(
94  headers_["X-Offer-Compression"] == "lz4" ? Compressed::On
95  : Compressed::Off)
96 {
97 }
98 
100 {
101  const bool inCluster{cluster()};
102 
103  if (state_ == State::active)
107 
108  if (inCluster)
109  {
110  JLOG(journal_.warn()) << getName() << " left cluster";
111  }
112 }
113 
114 // Helper function to check for valid uint256 values in protobuf buffers
115 static bool
117 {
118  return pBuffStr.size() == uint256::size();
119 }
120 
121 void
123 {
124  if (!strand_.running_in_this_thread())
125  return post(strand_, std::bind(&PeerImp::run, shared_from_this()));
126 
127  // We need to decipher
128  auto parseLedgerHash =
129  [](std::string const& value) -> boost::optional<uint256> {
130  uint256 ret;
131  if (ret.SetHexExact(value))
132  return {ret};
133 
134  auto const s = base64_decode(value);
135  if (s.size() != uint256::size())
136  return boost::none;
137  return uint256{s};
138  };
139 
140  boost::optional<uint256> closed;
141  boost::optional<uint256> previous;
142 
143  if (auto const iter = headers_.find("Closed-Ledger");
144  iter != headers_.end())
145  {
146  closed = parseLedgerHash(iter->value().to_string());
147 
148  if (!closed)
149  fail("Malformed handshake data (1)");
150  }
151 
152  if (auto const iter = headers_.find("Previous-Ledger");
153  iter != headers_.end())
154  {
155  previous = parseLedgerHash(iter->value().to_string());
156 
157  if (!previous)
158  fail("Malformed handshake data (2)");
159  }
160 
161  if (previous && !closed)
162  fail("Malformed handshake data (3)");
163 
164  {
166  if (closed)
167  closedLedgerHash_ = *closed;
168  if (previous)
169  previousLedgerHash_ = *previous;
170  }
171 
172  if (m_inbound)
173  {
174  doAccept();
175  }
176  else
177  {
178  assert(state_ == State::active);
179  // XXX Set timer: connection is in grace period to be useful.
180  // XXX Set timer: connection idle (idle may vary depending on connection
181  // type.)
182  doProtocolStart();
183  }
184 
185  // Request shard info from peer
186  protocol::TMGetPeerShardInfo tmGPS;
187  tmGPS.set_hops(0);
188  send(std::make_shared<Message>(tmGPS, protocol::mtGET_PEER_SHARD_INFO));
189 
190  setTimer();
191 }
192 
193 void
195 {
196  if (!strand_.running_in_this_thread())
197  return post(strand_, std::bind(&PeerImp::stop, shared_from_this()));
198  if (socket_.is_open())
199  {
200  // The rationale for using different severity levels is that
201  // outbound connections are under our control and may be logged
202  // at a higher level, but inbound connections are more numerous and
203  // uncontrolled so to prevent log flooding the severity is reduced.
204  //
205  if (m_inbound)
206  {
207  JLOG(journal_.debug()) << "Stop";
208  }
209  else
210  {
211  JLOG(journal_.info()) << "Stop";
212  }
213  }
214  close();
215 }
216 
217 //------------------------------------------------------------------------------
218 
219 void
221 {
222  if (!strand_.running_in_this_thread())
223  return post(strand_, std::bind(&PeerImp::send, shared_from_this(), m));
224  if (gracefulClose_)
225  return;
226  if (detaching_)
227  return;
228 
230  safe_cast<TrafficCount::category>(m->getCategory()),
231  false,
232  static_cast<int>(m->getBuffer(compressionEnabled_).size()));
233 
234  auto sendq_size = send_queue_.size();
235 
236  if (sendq_size < Tuning::targetSendQueue)
237  {
238  // To detect a peer that does not read from their
239  // side of the connection, we expect a peer to have
240  // a small senq periodically
241  large_sendq_ = 0;
242  }
243  else if (
245  (sendq_size % Tuning::sendQueueLogFreq) == 0)
246  {
247  std::string const name{getName()};
248  JLOG(journal_.debug())
249  << (name.empty() ? remote_address_.to_string() : name)
250  << " sendq: " << sendq_size;
251  }
252 
253  send_queue_.push(m);
254 
255  if (sendq_size != 0)
256  return;
257 
258  boost::asio::async_write(
259  stream_,
260  boost::asio::buffer(
261  send_queue_.front()->getBuffer(compressionEnabled_)),
262  bind_executor(
263  strand_,
264  std::bind(
267  std::placeholders::_1,
268  std::placeholders::_2)));
269 }
270 
271 void
273 {
274  if ((usage_.charge(fee) == Resource::drop) && usage_.disconnect() &&
275  strand_.running_in_this_thread())
276  {
277  // Sever the connection
279  fail("charge: Resources");
280  }
281 }
282 
283 //------------------------------------------------------------------------------
284 
285 bool
287 {
288  auto const iter = headers_.find("Crawl");
289  if (iter == headers_.end())
290  return false;
291  return boost::iequals(iter->value(), "public");
292 }
293 
294 bool
296 {
297  return static_cast<bool>(app_.cluster().member(publicKey_));
298 }
299 
302 {
303  if (m_inbound)
304  return headers_["User-Agent"].to_string();
305  return headers_["Server"].to_string();
306 }
307 
310 {
312 
313  ret[jss::public_key] = toBase58(TokenType::NodePublic, publicKey_);
314  ret[jss::address] = remote_address_.to_string();
315 
316  if (m_inbound)
317  ret[jss::inbound] = true;
318 
319  if (cluster())
320  {
321  ret[jss::cluster] = true;
322 
323  std::string name{getName()};
324  if (!name.empty())
325  // Could move here if Json::Value supported moving from a string
326  ret[jss::name] = name;
327  }
328 
329  ret[jss::load] = usage_.balance();
330 
331  {
332  auto const version = getVersion();
333  if (!version.empty())
334  ret[jss::version] = version;
335  }
336 
337  ret[jss::protocol] = to_string(protocol_);
338 
339  {
341  if (latency_)
342  ret[jss::latency] = static_cast<Json::UInt>(latency_->count());
343  }
344 
345  ret[jss::uptime] = static_cast<Json::UInt>(
346  std::chrono::duration_cast<std::chrono::seconds>(uptime()).count());
347 
348  std::uint32_t minSeq, maxSeq;
349  ledgerRange(minSeq, maxSeq);
350 
351  if ((minSeq != 0) || (maxSeq != 0))
352  ret[jss::complete_ledgers] =
353  std::to_string(minSeq) + " - " + std::to_string(maxSeq);
354 
355  switch (sanity_.load())
356  {
357  case Sanity::insane:
358  ret[jss::sanity] = "insane";
359  break;
360 
361  case Sanity::unknown:
362  ret[jss::sanity] = "unknown";
363  break;
364 
365  case Sanity::sane:
366  // Nothing to do here
367  break;
368  }
369 
370  uint256 closedLedgerHash;
371  protocol::TMStatusChange last_status;
372  {
374  closedLedgerHash = closedLedgerHash_;
375  last_status = last_status_;
376  }
377 
378  if (closedLedgerHash != beast::zero)
379  ret[jss::ledger] = to_string(closedLedgerHash);
380 
381  if (last_status.has_newstatus())
382  {
383  switch (last_status.newstatus())
384  {
385  case protocol::nsCONNECTING:
386  ret[jss::status] = "connecting";
387  break;
388 
389  case protocol::nsCONNECTED:
390  ret[jss::status] = "connected";
391  break;
392 
393  case protocol::nsMONITORING:
394  ret[jss::status] = "monitoring";
395  break;
396 
397  case protocol::nsVALIDATING:
398  ret[jss::status] = "validating";
399  break;
400 
401  case protocol::nsSHUTTING:
402  ret[jss::status] = "shutting";
403  break;
404 
405  default:
406  JLOG(p_journal_.warn())
407  << "Unknown status: " << last_status.newstatus();
408  }
409  }
410 
411  ret[jss::metrics] = Json::Value(Json::objectValue);
412  ret[jss::metrics][jss::total_bytes_recv] =
413  std::to_string(metrics_.recv.total_bytes());
414  ret[jss::metrics][jss::total_bytes_sent] =
415  std::to_string(metrics_.sent.total_bytes());
416  ret[jss::metrics][jss::avg_bps_recv] =
417  std::to_string(metrics_.recv.average_bytes());
418  ret[jss::metrics][jss::avg_bps_sent] =
419  std::to_string(metrics_.sent.average_bytes());
420 
421  return ret;
422 }
423 
424 bool
426 {
427  switch (f)
428  {
430  return protocol_ >= make_protocol(2, 1);
431  }
432  return false;
433 }
434 
435 //------------------------------------------------------------------------------
436 
437 bool
438 PeerImp::hasLedger(uint256 const& hash, std::uint32_t seq) const
439 {
440  {
442  if ((seq != 0) && (seq >= minLedger_) && (seq <= maxLedger_) &&
443  (sanity_.load() == Sanity::sane))
444  return true;
445  if (std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
446  recentLedgers_.end())
447  return true;
448  }
449 
450  return seq >= app_.getNodeStore().earliestLedgerSeq() &&
452 }
453 
454 void
456 {
458 
459  minSeq = minLedger_;
460  maxSeq = maxLedger_;
461 }
462 
463 bool
465 {
467  auto const it{shardInfo_.find(publicKey_)};
468  if (it != shardInfo_.end())
469  return boost::icl::contains(it->second.shardIndexes, shardIndex);
470  return false;
471 }
472 
473 bool
474 PeerImp::hasTxSet(uint256 const& hash) const
475 {
477  return std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
478  recentTxSets_.end();
479 }
480 
481 void
483 {
484  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
485  // guarded by recentLock_.
489 }
490 
491 bool
493 {
495  return (sanity_ != Sanity::insane) && (uMin >= minLedger_) &&
496  (uMax <= maxLedger_);
497 }
498 
499 //------------------------------------------------------------------------------
500 
501 void
503 {
504  assert(strand_.running_in_this_thread());
505  if (socket_.is_open())
506  {
507  detaching_ = true; // DEPRECATED
508  error_code ec;
509  timer_.cancel(ec);
510  socket_.close(ec);
512  if (m_inbound)
513  {
514  JLOG(journal_.debug()) << "Closed";
515  }
516  else
517  {
518  JLOG(journal_.info()) << "Closed";
519  }
520  }
521 }
522 
523 void
525 {
526  if (!strand_.running_in_this_thread())
527  return post(
528  strand_,
529  std::bind(
530  (void (Peer::*)(std::string const&)) & PeerImp::fail,
532  reason));
534  {
535  std::string const name{getName()};
536  JLOG(journal_.warn())
537  << (name.empty() ? remote_address_.to_string() : name)
538  << " failed: " << reason;
539  }
540  close();
541 }
542 
543 void
545 {
546  assert(strand_.running_in_this_thread());
547  if (socket_.is_open())
548  {
549  JLOG(journal_.warn())
550  << name << " from " << toBase58(TokenType::NodePublic, publicKey_)
551  << " at " << remote_address_.to_string() << ": " << ec.message();
552  }
553  close();
554 }
555 
556 boost::optional<RangeSet<std::uint32_t>>
558 {
560  auto it{shardInfo_.find(publicKey_)};
561  if (it != shardInfo_.end())
562  return it->second.shardIndexes;
563  return boost::none;
564 }
565 
566 boost::optional<hash_map<PublicKey, PeerImp::ShardInfo>>
568 {
570  if (!shardInfo_.empty())
571  return shardInfo_;
572  return boost::none;
573 }
574 
575 void
577 {
578  assert(strand_.running_in_this_thread());
579  assert(socket_.is_open());
580  assert(!gracefulClose_);
581  gracefulClose_ = true;
582 #if 0
583  // Flush messages
584  while(send_queue_.size() > 1)
585  send_queue_.pop_back();
586 #endif
587  if (send_queue_.size() > 0)
588  return;
589  setTimer();
590  stream_.async_shutdown(bind_executor(
591  strand_,
592  std::bind(
593  &PeerImp::onShutdown, shared_from_this(), std::placeholders::_1)));
594 }
595 
596 void
598 {
599  error_code ec;
600  timer_.expires_from_now(std::chrono::seconds(Tuning::timerSeconds), ec);
601 
602  if (ec)
603  {
604  JLOG(journal_.error()) << "setTimer: " << ec.message();
605  return;
606  }
607  timer_.async_wait(bind_executor(
608  strand_,
609  std::bind(
610  &PeerImp::onTimer, shared_from_this(), std::placeholders::_1)));
611 }
612 
613 // convenience for ignoring the error code
614 void
616 {
617  error_code ec;
618  timer_.cancel(ec);
619 }
620 
621 //------------------------------------------------------------------------------
622 
625 {
627  ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
628  return ss.str();
629 }
630 
631 void
633 {
634  if (!socket_.is_open())
635  return;
636 
637  if (ec == boost::asio::error::operation_aborted)
638  return;
639 
640  if (ec)
641  {
642  // This should never happen
643  JLOG(journal_.error()) << "onTimer: " << ec.message();
644  return close();
645  }
646 
648  {
649  fail("Large send queue");
650  return;
651  }
652 
653  bool failedNoPing{false};
654  boost::optional<std::uint32_t> pingSeq;
655  // Operations on lastPingSeq_, lastPingTime_, no_ping_, and latency_
656  // must be guarded by recentLock_.
657  {
659  if (no_ping_++ >= Tuning::noPing)
660  {
661  failedNoPing = true;
662  }
663  else if (!lastPingSeq_)
664  {
665  // Make the sequence unpredictable enough to prevent guessing
666  lastPingSeq_ = rand_int<std::uint32_t>();
668  pingSeq = lastPingSeq_;
669  }
670  else
671  {
672  // We have an outstanding ping, raise latency
673  auto const minLatency =
674  std::chrono::duration_cast<std::chrono::milliseconds>(
676 
677  if (latency_ < minLatency)
678  latency_ = minLatency;
679  }
680  }
681 
682  if (failedNoPing)
683  {
684  fail("No ping reply received");
685  return;
686  }
687 
688  if (pingSeq)
689  {
690  protocol::TMPing message;
691  message.set_type(protocol::TMPing::ptPING);
692  message.set_seq(*pingSeq);
693 
694  send(std::make_shared<Message>(message, protocol::mtPING));
695  }
696 
697  setTimer();
698 }
699 
700 void
702 {
703  cancelTimer();
704  // If we don't get eof then something went wrong
705  if (!ec)
706  {
707  JLOG(journal_.error()) << "onShutdown: expected error condition";
708  return close();
709  }
710  if (ec != boost::asio::error::eof)
711  return fail("onShutdown", ec);
712  close();
713 }
714 
715 //------------------------------------------------------------------------------
716 
717 void
719 {
720  assert(read_buffer_.size() == 0);
721 
722  JLOG(journal_.debug()) << "doAccept: " << remote_address_;
723 
724  auto const sharedValue = makeSharedValue(*stream_ptr_, journal_);
725 
726  // This shouldn't fail since we already computed
727  // the shared value successfully in OverlayImpl
728  if (!sharedValue)
729  return fail("makeSharedValue: Unexpected failure");
730 
731  // TODO Apply headers to connection state.
732 
733  boost::beast::ostream(write_buffer_) << makeResponse(
735  request_,
737  *sharedValue);
738 
739  JLOG(journal_.info()) << "Protocol: " << to_string(protocol_);
740  JLOG(journal_.info()) << "Public Key: "
742 
743  if (auto member = app_.cluster().member(publicKey_))
744  {
745  {
747  name_ = *member;
748  }
749  JLOG(journal_.info()) << "Cluster name: " << *member;
750  }
751 
753 
754  // XXX Set timer: connection is in grace period to be useful.
755  // XXX Set timer: connection idle (idle may vary depending on connection
756  // type.)
757 
759 }
760 
763  bool crawl,
764  http_request_type const& req,
765  beast::IP::Address remote_ip,
766  uint256 const& sharedValue)
767 {
768  http_response_type resp;
769  resp.result(boost::beast::http::status::switching_protocols);
770  resp.version(req.version());
771  resp.insert("Connection", "Upgrade");
772  resp.insert("Upgrade", to_string(protocol_));
773  resp.insert("Connect-As", "Peer");
774  resp.insert("Server", BuildInfo::getFullVersionString());
775  resp.insert("Crawl", crawl ? "public" : "private");
776  if (req["X-Offer-Compression"] == "lz4" && app_.config().COMPRESSION)
777  resp.insert("X-Offer-Compression", "lz4");
778 
780  resp,
781  sharedValue,
784  remote_ip,
785  app_);
786 
787  return resp;
788 }
789 
790 // Called repeatedly to send the bytes in the response
791 void
793 {
794  if (!socket_.is_open())
795  return;
796  if (ec == boost::asio::error::operation_aborted)
797  return;
798  if (ec)
799  return fail("onWriteResponse", ec);
800  if (auto stream = journal_.trace())
801  {
802  if (bytes_transferred > 0)
803  stream << "onWriteResponse: " << bytes_transferred << " bytes";
804  else
805  stream << "onWriteResponse";
806  }
807 
808  write_buffer_.consume(bytes_transferred);
809  if (write_buffer_.size() == 0)
810  return doProtocolStart();
811 
812  stream_.async_write_some(
813  write_buffer_.data(),
814  bind_executor(
815  strand_,
816  std::bind(
819  std::placeholders::_1,
820  std::placeholders::_2)));
821 }
822 
825 {
827  return name_;
828 }
829 
830 //------------------------------------------------------------------------------
831 
832 // Protocol logic
833 
834 void
836 {
838 
839  // Send all the validator lists that have been loaded
841  {
843  std::string const& blob,
844  std::string const& signature,
845  std::uint32_t version,
846  PublicKey const& pubKey,
847  std::size_t sequence,
848  uint256 const& hash) {
849  protocol::TMValidatorList vl;
850 
851  vl.set_manifest(manifest);
852  vl.set_blob(blob);
853  vl.set_signature(signature);
854  vl.set_version(version);
855 
856  JLOG(p_journal_.debug())
857  << "Sending validator list for " << strHex(pubKey)
858  << " with sequence " << sequence << " to "
859  << remote_address_.to_string() << " (" << id_ << ")";
860  auto m = std::make_shared<Message>(vl, protocol::mtVALIDATORLIST);
861  send(m);
862  // Don't send it next time.
864  setPublisherListSequence(pubKey, sequence);
865  });
866  }
867 
868  protocol::TMManifests tm;
869 
871  [&tm](std::size_t s) { tm.mutable_list()->Reserve(s); },
872  [&tm, &hr = app_.getHashRouter()](Manifest const& manifest) {
873  auto const& s = manifest.serialized;
874  auto& tm_e = *tm.add_list();
875  tm_e.set_stobject(s.data(), s.size());
876  hr.addSuppression(manifest.hash());
877  });
878 
879  if (tm.list_size() > 0)
880  {
881  auto m = std::make_shared<Message>(tm, protocol::mtMANIFESTS);
882  send(m);
883  }
884 }
885 
886 // Called repeatedly with protocol message data
887 void
889 {
890  if (!socket_.is_open())
891  return;
892  if (ec == boost::asio::error::operation_aborted)
893  return;
894  if (ec == boost::asio::error::eof)
895  {
896  JLOG(journal_.info()) << "EOF";
897  return gracefulClose();
898  }
899  if (ec)
900  return fail("onReadMessage", ec);
901  if (auto stream = journal_.trace())
902  {
903  if (bytes_transferred > 0)
904  stream << "onReadMessage: " << bytes_transferred << " bytes";
905  else
906  stream << "onReadMessage";
907  }
908 
909  metrics_.recv.add_message(bytes_transferred);
910 
911  read_buffer_.commit(bytes_transferred);
912 
913  while (read_buffer_.size() > 0)
914  {
915  std::size_t bytes_consumed;
916  std::tie(bytes_consumed, ec) =
917  invokeProtocolMessage(read_buffer_.data(), *this);
918  if (ec)
919  return fail("onReadMessage", ec);
920  if (!socket_.is_open())
921  return;
922  if (gracefulClose_)
923  return;
924  if (bytes_consumed == 0)
925  break;
926  read_buffer_.consume(bytes_consumed);
927  }
928  // Timeout on writes only
929  stream_.async_read_some(
931  bind_executor(
932  strand_,
933  std::bind(
936  std::placeholders::_1,
937  std::placeholders::_2)));
938 }
939 
940 void
942 {
943  if (!socket_.is_open())
944  return;
945  if (ec == boost::asio::error::operation_aborted)
946  return;
947  if (ec)
948  return fail("onWriteMessage", ec);
949  if (auto stream = journal_.trace())
950  {
951  if (bytes_transferred > 0)
952  stream << "onWriteMessage: " << bytes_transferred << " bytes";
953  else
954  stream << "onWriteMessage";
955  }
956 
957  metrics_.sent.add_message(bytes_transferred);
958 
959  assert(!send_queue_.empty());
960  send_queue_.pop();
961  if (!send_queue_.empty())
962  {
963  // Timeout on writes only
964  return boost::asio::async_write(
965  stream_,
966  boost::asio::buffer(
967  send_queue_.front()->getBuffer(compressionEnabled_)),
968  bind_executor(
969  strand_,
970  std::bind(
973  std::placeholders::_1,
974  std::placeholders::_2)));
975  }
976 
977  if (gracefulClose_)
978  {
979  return stream_.async_shutdown(bind_executor(
980  strand_,
981  std::bind(
984  std::placeholders::_1)));
985  }
986 }
987 
988 //------------------------------------------------------------------------------
989 //
990 // ProtocolHandler
991 //
992 //------------------------------------------------------------------------------
993 
994 void
996 {
997  // TODO
998 }
999 
1000 void
1002  std::uint16_t type,
1004  std::size_t size)
1005 {
1006  load_event_ =
1010  TrafficCount::categorize(*m, type, true), true, static_cast<int>(size));
1011 }
1012 
1013 void
1015  std::uint16_t,
1017 {
1018  load_event_.reset();
1019  charge(fee_);
1020 }
1021 
1022 void
1024 {
1025  // VFALCO What's the right job type?
1026  auto that = shared_from_this();
1028  jtVALIDATION_ut, "receiveManifests", [this, that, m](Job&) {
1029  overlay_.onManifests(m, that);
1030  });
1031 }
1032 
1033 void
1035 {
1036  if (m->type() == protocol::TMPing::ptPING)
1037  {
1038  // We have received a ping request, reply with a pong
1040  m->set_type(protocol::TMPing::ptPONG);
1041  send(std::make_shared<Message>(*m, protocol::mtPING));
1042  return;
1043  }
1044 
1045  if (m->type() == protocol::TMPing::ptPONG)
1046  {
1047  // Operations on lastPingSeq_, lastPingTime_, no_ping_, and latency_
1048  // must be guarded by recentLock_.
1050 
1051  if (m->has_seq() && m->seq() == lastPingSeq_)
1052  {
1053  no_ping_ = 0;
1054 
1055  // Only reset the ping sequence if we actually received a
1056  // PONG with the correct cookie. That way, any peers which
1057  // respond with incorrect cookies will eventually time out.
1058  lastPingSeq_.reset();
1059 
1060  // Update latency estimate
1061  auto const estimate =
1062  std::chrono::duration_cast<std::chrono::milliseconds>(
1064 
1065  // Calculate the cumulative moving average of the latency:
1066  if (latency_)
1067  latency_ = (*latency_ * 7 + estimate) / 8;
1068  else
1069  latency_ = estimate;
1070  }
1071 
1072  return;
1073  }
1074 }
1075 
1076 void
1078 {
1079  // VFALCO NOTE I think we should drop the peer immediately
1080  if (!cluster())
1081  {
1083  return;
1084  }
1085 
1086  for (int i = 0; i < m->clusternodes().size(); ++i)
1087  {
1088  protocol::TMClusterNode const& node = m->clusternodes(i);
1089 
1090  std::string name;
1091  if (node.has_nodename())
1092  name = node.nodename();
1093 
1094  auto const publicKey =
1095  parseBase58<PublicKey>(TokenType::NodePublic, node.publickey());
1096 
1097  // NIKB NOTE We should drop the peer immediately if
1098  // they send us a public key we can't parse
1099  if (publicKey)
1100  {
1101  auto const reportTime =
1102  NetClock::time_point{NetClock::duration{node.reporttime()}};
1103 
1104  app_.cluster().update(
1105  *publicKey, name, node.nodeload(), reportTime);
1106  }
1107  }
1108 
1109  int loadSources = m->loadsources().size();
1110  if (loadSources != 0)
1111  {
1112  Resource::Gossip gossip;
1113  gossip.items.reserve(loadSources);
1114  for (int i = 0; i < m->loadsources().size(); ++i)
1115  {
1116  protocol::TMLoadSource const& node = m->loadsources(i);
1118  item.address = beast::IP::Endpoint::from_string(node.name());
1119  item.balance = node.cost();
1120  if (item.address != beast::IP::Endpoint())
1121  gossip.items.push_back(item);
1122  }
1124  }
1125 
1126  // Calculate the cluster fee:
1127  auto const thresh = app_.timeKeeper().now() - 90s;
1128  std::uint32_t clusterFee = 0;
1129 
1131  fees.reserve(app_.cluster().size());
1132 
1133  app_.cluster().for_each([&fees, thresh](ClusterNode const& status) {
1134  if (status.getReportTime() >= thresh)
1135  fees.push_back(status.getLoadFee());
1136  });
1137 
1138  if (!fees.empty())
1139  {
1140  auto const index = fees.size() / 2;
1141  std::nth_element(fees.begin(), fees.begin() + index, fees.end());
1142  clusterFee = fees[index];
1143  }
1144 
1145  app_.getFeeTrack().setClusterFee(clusterFee);
1146 }
1147 
1148 void
1150 {
1151  // DEPRECATED
1152 }
1153 
1154 void
1156 {
1157  // DEPRECATED
1158 }
1159 
1160 void
1162 {
1163  auto badData = [&](std::string msg) {
1165  JLOG(p_journal_.warn()) << msg;
1166  };
1167 
1168  if (m->hops() > csHopLimit)
1169  return badData("Invalid hops: " + std::to_string(m->hops()));
1170  if (m->peerchain_size() > csHopLimit)
1171  return badData("Invalid peer chain");
1172 
1173  // Reply with shard info we may have
1174  if (auto shardStore = app_.getShardStore())
1175  {
1177  auto shards{shardStore->getCompleteShards()};
1178  if (!shards.empty())
1179  {
1180  protocol::TMPeerShardInfo reply;
1181  reply.set_shardindexes(shards);
1182 
1183  if (m->has_lastlink())
1184  reply.set_lastlink(true);
1185 
1186  if (m->peerchain_size() > 0)
1187  {
1188  for (int i = 0; i < m->peerchain_size(); ++i)
1189  {
1190  if (!publicKeyType(makeSlice(m->peerchain(i).nodepubkey())))
1191  return badData("Invalid peer chain public key");
1192  }
1193 
1194  *reply.mutable_peerchain() = m->peerchain();
1195  }
1196 
1197  send(std::make_shared<Message>(reply, protocol::mtPEER_SHARD_INFO));
1198 
1199  JLOG(p_journal_.trace()) << "Sent shard indexes " << shards;
1200  }
1201  }
1202 
1203  // Relay request to peers
1204  if (m->hops() > 0)
1205  {
1207 
1208  m->set_hops(m->hops() - 1);
1209  if (m->hops() == 0)
1210  m->set_lastlink(true);
1211 
1212  m->add_peerchain()->set_nodepubkey(
1214 
1216  std::make_shared<Message>(*m, protocol::mtGET_PEER_SHARD_INFO),
1217  match_peer(this)));
1218  }
1219 }
1220 
1221 void
1223 {
1224  auto badData = [&](std::string msg) {
1226  JLOG(p_journal_.warn()) << msg;
1227  };
1228 
1229  if (m->shardindexes().empty())
1230  return badData("Missing shard indexes");
1231  if (m->peerchain_size() > csHopLimit)
1232  return badData("Invalid peer chain");
1233  if (m->has_nodepubkey() && !publicKeyType(makeSlice(m->nodepubkey())))
1234  return badData("Invalid public key");
1235 
1236  // Check if the message should be forwarded to another peer
1237  if (m->peerchain_size() > 0)
1238  {
1239  // Get the Public key of the last link in the peer chain
1240  auto const s{
1241  makeSlice(m->peerchain(m->peerchain_size() - 1).nodepubkey())};
1242  if (!publicKeyType(s))
1243  return badData("Invalid pubKey");
1244  PublicKey peerPubKey(s);
1245 
1246  if (auto peer = overlay_.findPeerByPublicKey(peerPubKey))
1247  {
1248  if (!m->has_nodepubkey())
1249  m->set_nodepubkey(publicKey_.data(), publicKey_.size());
1250 
1251  if (!m->has_endpoint())
1252  {
1253  // Check if peer will share IP publicly
1254  if (crawl())
1255  m->set_endpoint(remote_address_.address().to_string());
1256  else
1257  m->set_endpoint("0");
1258  }
1259 
1260  m->mutable_peerchain()->RemoveLast();
1261  peer->send(
1262  std::make_shared<Message>(*m, protocol::mtPEER_SHARD_INFO));
1263 
1264  JLOG(p_journal_.trace())
1265  << "Relayed TMPeerShardInfo to peer with IP "
1266  << remote_address_.address().to_string();
1267  }
1268  else
1269  {
1270  // Peer is no longer available so the relay ends
1272  JLOG(p_journal_.info()) << "Unable to route shard info";
1273  }
1274  return;
1275  }
1276 
1277  // Parse the shard indexes received in the shard info
1278  RangeSet<std::uint32_t> shardIndexes;
1279  {
1280  if (!from_string(shardIndexes, m->shardindexes()))
1281  return badData("Invalid shard indexes");
1282 
1283  std::uint32_t earliestShard;
1284  boost::optional<std::uint32_t> latestShard;
1285  {
1286  auto const curLedgerSeq{
1288  if (auto shardStore = app_.getShardStore())
1289  {
1290  earliestShard = shardStore->earliestShardIndex();
1291  if (curLedgerSeq >= shardStore->earliestLedgerSeq())
1292  latestShard = shardStore->seqToShardIndex(curLedgerSeq);
1293  }
1294  else
1295  {
1296  auto const earliestLedgerSeq{
1298  earliestShard = NodeStore::seqToShardIndex(earliestLedgerSeq);
1299  if (curLedgerSeq >= earliestLedgerSeq)
1300  latestShard = NodeStore::seqToShardIndex(curLedgerSeq);
1301  }
1302  }
1303 
1304  if (boost::icl::first(shardIndexes) < earliestShard ||
1305  (latestShard && boost::icl::last(shardIndexes) > latestShard))
1306  {
1307  return badData("Invalid shard indexes");
1308  }
1309  }
1310 
1311  // Get the IP of the node reporting the shard info
1312  beast::IP::Endpoint endpoint;
1313  if (m->has_endpoint())
1314  {
1315  if (m->endpoint() != "0")
1316  {
1317  auto result =
1319  if (!result)
1320  return badData("Invalid incoming endpoint: " + m->endpoint());
1321  endpoint = std::move(*result);
1322  }
1323  }
1324  else if (crawl()) // Check if peer will share IP publicly
1325  {
1326  endpoint = remote_address_;
1327  }
1328 
1329  // Get the Public key of the node reporting the shard info
1330  PublicKey publicKey;
1331  if (m->has_nodepubkey())
1332  publicKey = PublicKey(makeSlice(m->nodepubkey()));
1333  else
1334  publicKey = publicKey_;
1335 
1336  {
1338  auto it{shardInfo_.find(publicKey)};
1339  if (it != shardInfo_.end())
1340  {
1341  // Update the IP address for the node
1342  it->second.endpoint = std::move(endpoint);
1343 
1344  // Join the shard index range set
1345  it->second.shardIndexes += shardIndexes;
1346  }
1347  else
1348  {
1349  // Add a new node
1350  ShardInfo shardInfo;
1351  shardInfo.endpoint = std::move(endpoint);
1352  shardInfo.shardIndexes = std::move(shardIndexes);
1353  shardInfo_.emplace(publicKey, std::move(shardInfo));
1354  }
1355  }
1356 
1357  JLOG(p_journal_.trace())
1358  << "Consumed TMPeerShardInfo originating from public key "
1359  << toBase58(TokenType::NodePublic, publicKey) << " shard indexes "
1360  << m->shardindexes();
1361 
1362  if (m->has_lastlink())
1364 }
1365 
1366 void
1368 {
1369  if (sanity_.load() != Sanity::sane)
1370  {
1371  // Don't allow endpoints from peer not known sane
1372  return;
1373  }
1374 
1376 
1377  if (m->endpoints_v2().size())
1378  {
1379  endpoints.reserve(m->endpoints_v2().size());
1380  for (auto const& tm : m->endpoints_v2())
1381  {
1382  // these endpoint strings support ipv4 and ipv6
1383  auto result =
1385  if (!result)
1386  {
1387  JLOG(p_journal_.error())
1388  << "failed to parse incoming endpoint: {" << tm.endpoint()
1389  << "}";
1390  continue;
1391  }
1392 
1393  // If hops == 0, this Endpoint describes the peer we are connected
1394  // to -- in that case, we take the remote address seen on the
1395  // socket and store that in the IP::Endpoint. If this is the first
1396  // time, then we'll verify that their listener can receive incoming
1397  // by performing a connectivity test. if hops > 0, then we just
1398  // take the address/port we were given
1399 
1400  endpoints.emplace_back(
1401  tm.hops() > 0 ? *result
1402  : remote_address_.at_port(result->port()),
1403  tm.hops());
1404  JLOG(p_journal_.trace())
1405  << "got v2 EP: " << endpoints.back().address
1406  << ", hops = " << endpoints.back().hops;
1407  }
1408  }
1409  else
1410  {
1411  // this branch can be removed once the entire network is operating with
1412  // endpoint_v2() items (strings)
1413  endpoints.reserve(m->endpoints().size());
1414  for (int i = 0; i < m->endpoints().size(); ++i)
1415  {
1416  PeerFinder::Endpoint endpoint;
1417  protocol::TMEndpoint const& tm(m->endpoints(i));
1418 
1419  // hops
1420  endpoint.hops = tm.hops();
1421 
1422  // ipv4
1423  if (endpoint.hops > 0)
1424  {
1425  in_addr addr;
1426  addr.s_addr = tm.ipv4().ipv4();
1427  beast::IP::AddressV4 v4(ntohl(addr.s_addr));
1428  endpoint.address =
1429  beast::IP::Endpoint(v4, tm.ipv4().ipv4port());
1430  }
1431  else
1432  {
1433  // This Endpoint describes the peer we are connected to.
1434  // We will take the remote address seen on the socket and
1435  // store that in the IP::Endpoint. If this is the first time,
1436  // then we'll verify that their listener can receive incoming
1437  // by performing a connectivity test.
1438  //
1439  endpoint.address =
1440  remote_address_.at_port(tm.ipv4().ipv4port());
1441  }
1442  endpoints.push_back(endpoint);
1443  JLOG(p_journal_.trace())
1444  << "got v1 EP: " << endpoints.back().address
1445  << ", hops = " << endpoints.back().hops;
1446  }
1447  }
1448 
1449  if (!endpoints.empty())
1450  overlay_.peerFinder().on_endpoints(slot_, endpoints);
1451 }
1452 
1453 void
1455 {
1456  if (sanity_.load() == Sanity::insane)
1457  return;
1458 
1460  {
1461  // If we've never been in synch, there's nothing we can do
1462  // with a transaction
1463  JLOG(p_journal_.debug()) << "Ignoring incoming transaction: "
1464  << "Need network ledger";
1465  return;
1466  }
1467 
1468  SerialIter sit(makeSlice(m->rawtransaction()));
1469 
1470  try
1471  {
1472  auto stx = std::make_shared<STTx const>(sit);
1473  uint256 txID = stx->getTransactionID();
1474 
1475  int flags;
1476  constexpr std::chrono::seconds tx_interval = 10s;
1477 
1478  if (!app_.getHashRouter().shouldProcess(txID, id_, flags, tx_interval))
1479  {
1480  // we have seen this transaction recently
1481  if (flags & SF_BAD)
1482  {
1484  JLOG(p_journal_.debug()) << "Ignoring known bad tx " << txID;
1485  }
1486 
1487  return;
1488  }
1489 
1490  JLOG(p_journal_.debug()) << "Got tx " << txID;
1491 
1492  bool checkSignature = true;
1493  if (cluster())
1494  {
1495  if (!m->has_deferred() || !m->deferred())
1496  {
1497  // Skip local checks if a server we trust
1498  // put the transaction in its open ledger
1499  flags |= SF_TRUSTED;
1500  }
1501 
1503  {
1504  // For now, be paranoid and have each validator
1505  // check each transaction, regardless of source
1506  checkSignature = false;
1507  }
1508  }
1509 
1510  // The maximum number of transactions to have in the job queue.
1511  constexpr int max_transactions = 250;
1512  if (app_.getJobQueue().getJobCount(jtTRANSACTION) > max_transactions)
1513  {
1515  JLOG(p_journal_.info()) << "Transaction queue is full";
1516  }
1517  else if (app_.getLedgerMaster().getValidatedLedgerAge() > 4min)
1518  {
1519  JLOG(p_journal_.trace())
1520  << "No new transactions until synchronized";
1521  }
1522  else
1523  {
1525  jtTRANSACTION,
1526  "recvTransaction->checkTransaction",
1528  flags,
1529  checkSignature,
1530  stx](Job&) {
1531  if (auto peer = weak.lock())
1532  peer->checkTransaction(flags, checkSignature, stx);
1533  });
1534  }
1535  }
1536  catch (std::exception const&)
1537  {
1538  JLOG(p_journal_.warn())
1539  << "Transaction invalid: " << strHex(m->rawtransaction());
1540  }
1541 }
1542 
1543 void
1545 {
1548  app_.getJobQueue().addJob(jtLEDGER_REQ, "recvGetLedger", [weak, m](Job&) {
1549  if (auto peer = weak.lock())
1550  peer->getLedger(m);
1551  });
1552 }
1553 
1554 void
1556 {
1557  protocol::TMLedgerData& packet = *m;
1558 
1559  if (m->nodes().size() <= 0)
1560  {
1561  JLOG(p_journal_.warn()) << "Ledger/TXset data with no nodes";
1562  return;
1563  }
1564 
1565  if (m->has_requestcookie())
1566  {
1567  std::shared_ptr<Peer> target =
1568  overlay_.findPeerByShortID(m->requestcookie());
1569  if (target)
1570  {
1571  m->clear_requestcookie();
1572  target->send(
1573  std::make_shared<Message>(packet, protocol::mtLEDGER_DATA));
1574  }
1575  else
1576  {
1577  JLOG(p_journal_.info()) << "Unable to route TX/ledger data reply";
1579  }
1580  return;
1581  }
1582 
1583  if (!stringIsUint256Sized(m->ledgerhash()))
1584  {
1585  JLOG(p_journal_.warn()) << "TX candidate reply with invalid hash size";
1587  return;
1588  }
1589 
1590  uint256 const hash{m->ledgerhash()};
1591 
1592  if (m->type() == protocol::liTS_CANDIDATE)
1593  {
1594  // got data for a candidate transaction set
1597  jtTXN_DATA, "recvPeerData", [weak, hash, m](Job&) {
1598  if (auto peer = weak.lock())
1599  peer->app_.getInboundTransactions().gotData(hash, peer, m);
1600  });
1601  return;
1602  }
1603 
1605  {
1606  JLOG(p_journal_.trace()) << "Got data for unwanted ledger";
1608  }
1609 }
1610 
1611 void
1613 {
1614  protocol::TMProposeSet& set = *m;
1615 
1616  auto const sig = makeSlice(set.signature());
1617 
1618  // Preliminary check for the validity of the signature: A DER encoded
1619  // signature can't be longer than 72 bytes.
1620  if ((boost::algorithm::clamp(sig.size(), 64, 72) != sig.size()) ||
1621  (publicKeyType(makeSlice(set.nodepubkey())) != KeyType::secp256k1))
1622  {
1623  JLOG(p_journal_.warn()) << "Proposal: malformed";
1625  return;
1626  }
1627 
1628  if (!stringIsUint256Sized(set.currenttxhash()) ||
1629  !stringIsUint256Sized(set.previousledger()))
1630  {
1631  JLOG(p_journal_.warn()) << "Proposal: malformed";
1633  return;
1634  }
1635 
1636  uint256 const proposeHash{set.currenttxhash()};
1637  uint256 const prevLedger{set.previousledger()};
1638 
1639  PublicKey const publicKey{makeSlice(set.nodepubkey())};
1640  NetClock::time_point const closeTime{NetClock::duration{set.closetime()}};
1641 
1642  uint256 const suppression = proposalUniqueId(
1643  proposeHash,
1644  prevLedger,
1645  set.proposeseq(),
1646  closeTime,
1647  publicKey.slice(),
1648  sig);
1649 
1650  if (!app_.getHashRouter().addSuppressionPeer(suppression, id_))
1651  {
1652  JLOG(p_journal_.trace()) << "Proposal: duplicate";
1653  return;
1654  }
1655 
1656  auto const isTrusted = app_.validators().trusted(publicKey);
1657 
1658  if (!isTrusted)
1659  {
1660  if (sanity_.load() == Sanity::insane)
1661  {
1662  JLOG(p_journal_.debug()) << "Proposal: Dropping UNTRUSTED (insane)";
1663  return;
1664  }
1665 
1666  if (!cluster() && app_.getFeeTrack().isLoadedLocal())
1667  {
1668  JLOG(p_journal_.debug()) << "Proposal: Dropping UNTRUSTED (load)";
1669  return;
1670  }
1671  }
1672 
1673  JLOG(p_journal_.trace())
1674  << "Proposal: " << (isTrusted ? "trusted" : "UNTRUSTED");
1675 
1676  auto proposal = RCLCxPeerPos(
1677  publicKey,
1678  sig,
1679  suppression,
1681  prevLedger,
1682  set.proposeseq(),
1683  proposeHash,
1684  closeTime,
1687 
1690  isTrusted ? jtPROPOSAL_t : jtPROPOSAL_ut,
1691  "recvPropose->checkPropose",
1692  [weak, m, proposal](Job& job) {
1693  if (auto peer = weak.lock())
1694  peer->checkPropose(job, m, proposal);
1695  });
1696 }
1697 
1698 void
1700 {
1701  JLOG(p_journal_.trace()) << "Status: Change";
1702 
1703  if (!m->has_networktime())
1704  m->set_networktime(app_.timeKeeper().now().time_since_epoch().count());
1705 
1706  {
1708  if (!last_status_.has_newstatus() || m->has_newstatus())
1709  last_status_ = *m;
1710  else
1711  {
1712  // preserve old status
1713  protocol::NodeStatus status = last_status_.newstatus();
1714  last_status_ = *m;
1715  m->set_newstatus(status);
1716  }
1717  }
1718 
1719  if (m->newevent() == protocol::neLOST_SYNC)
1720  {
1721  bool outOfSync{false};
1722  {
1723  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
1724  // guarded by recentLock_.
1726  if (!closedLedgerHash_.isZero())
1727  {
1728  outOfSync = true;
1730  }
1732  }
1733  if (outOfSync)
1734  {
1735  JLOG(p_journal_.debug()) << "Status: Out of sync";
1736  }
1737  return;
1738  }
1739 
1740  {
1741  uint256 closedLedgerHash{};
1742  bool const peerChangedLedgers{
1743  m->has_ledgerhash() && stringIsUint256Sized(m->ledgerhash())};
1744 
1745  {
1746  // Operations on closedLedgerHash_ and previousLedgerHash_ must be
1747  // guarded by recentLock_.
1749  if (peerChangedLedgers)
1750  {
1751  closedLedgerHash_ = m->ledgerhash();
1752  closedLedgerHash = closedLedgerHash_;
1753  addLedger(closedLedgerHash, sl);
1754  }
1755  else
1756  {
1758  }
1759 
1760  if (m->has_ledgerhashprevious() &&
1761  stringIsUint256Sized(m->ledgerhashprevious()))
1762  {
1763  previousLedgerHash_ = m->ledgerhashprevious();
1765  }
1766  else
1767  {
1769  }
1770  }
1771  if (peerChangedLedgers)
1772  {
1773  JLOG(p_journal_.debug()) << "LCL is " << closedLedgerHash;
1774  }
1775  else
1776  {
1777  JLOG(p_journal_.debug()) << "Status: No ledger";
1778  }
1779  }
1780 
1781  if (m->has_firstseq() && m->has_lastseq())
1782  {
1784 
1785  minLedger_ = m->firstseq();
1786  maxLedger_ = m->lastseq();
1787 
1788  if ((maxLedger_ < minLedger_) || (minLedger_ == 0) || (maxLedger_ == 0))
1789  minLedger_ = maxLedger_ = 0;
1790  }
1791 
1792  if (m->has_ledgerseq() &&
1794  {
1795  checkSanity(
1796  m->ledgerseq(), app_.getLedgerMaster().getValidLedgerIndex());
1797  }
1798 
1799  app_.getOPs().pubPeerStatus([=]() -> Json::Value {
1801 
1802  if (m->has_newstatus())
1803  {
1804  switch (m->newstatus())
1805  {
1806  case protocol::nsCONNECTING:
1807  j[jss::status] = "CONNECTING";
1808  break;
1809  case protocol::nsCONNECTED:
1810  j[jss::status] = "CONNECTED";
1811  break;
1812  case protocol::nsMONITORING:
1813  j[jss::status] = "MONITORING";
1814  break;
1815  case protocol::nsVALIDATING:
1816  j[jss::status] = "VALIDATING";
1817  break;
1818  case protocol::nsSHUTTING:
1819  j[jss::status] = "SHUTTING";
1820  break;
1821  }
1822  }
1823 
1824  if (m->has_newevent())
1825  {
1826  switch (m->newevent())
1827  {
1828  case protocol::neCLOSING_LEDGER:
1829  j[jss::action] = "CLOSING_LEDGER";
1830  break;
1831  case protocol::neACCEPTED_LEDGER:
1832  j[jss::action] = "ACCEPTED_LEDGER";
1833  break;
1834  case protocol::neSWITCHED_LEDGER:
1835  j[jss::action] = "SWITCHED_LEDGER";
1836  break;
1837  case protocol::neLOST_SYNC:
1838  j[jss::action] = "LOST_SYNC";
1839  break;
1840  }
1841  }
1842 
1843  if (m->has_ledgerseq())
1844  {
1845  j[jss::ledger_index] = m->ledgerseq();
1846  }
1847 
1848  if (m->has_ledgerhash())
1849  {
1850  uint256 closedLedgerHash{};
1851  {
1852  std::lock_guard sl(recentLock_);
1853  closedLedgerHash = closedLedgerHash_;
1854  }
1855  j[jss::ledger_hash] = to_string(closedLedgerHash);
1856  }
1857 
1858  if (m->has_networktime())
1859  {
1860  j[jss::date] = Json::UInt(m->networktime());
1861  }
1862 
1863  if (m->has_firstseq() && m->has_lastseq())
1864  {
1865  j[jss::ledger_index_min] = Json::UInt(m->firstseq());
1866  j[jss::ledger_index_max] = Json::UInt(m->lastseq());
1867  }
1868 
1869  return j;
1870  });
1871 }
1872 
1873 void
1874 PeerImp::checkSanity(std::uint32_t validationSeq)
1875 {
1876  std::uint32_t serverSeq;
1877  {
1878  // Extract the seqeuence number of the highest
1879  // ledger this peer has
1880  std::lock_guard sl(recentLock_);
1881 
1882  serverSeq = maxLedger_;
1883  }
1884  if (serverSeq != 0)
1885  {
1886  // Compare the peer's ledger sequence to the
1887  // sequence of a recently-validated ledger
1888  checkSanity(serverSeq, validationSeq);
1889  }
1890 }
1891 
1892 void
1893 PeerImp::checkSanity(std::uint32_t seq1, std::uint32_t seq2)
1894 {
1895  int diff = std::max(seq1, seq2) - std::min(seq1, seq2);
1896 
1897  if (diff < Tuning::saneLedgerLimit)
1898  {
1899  // The peer's ledger sequence is close to the validation's
1900  sanity_ = Sanity::sane;
1901  }
1902 
1903  if ((diff > Tuning::insaneLedgerLimit) &&
1904  (sanity_.load() != Sanity::insane))
1905  {
1906  // The peer's ledger sequence is way off the validation's
1907  std::lock_guard sl(recentLock_);
1908 
1909  sanity_ = Sanity::insane;
1910  insaneTime_ = clock_type::now();
1911  }
1912 }
1913 
1914 // Should this connection be rejected
1915 // and considered a failure
1916 void
1917 PeerImp::check()
1918 {
1919  if (m_inbound || (sanity_.load() == Sanity::sane))
1920  return;
1921 
1922  clock_type::time_point insaneTime;
1923  {
1924  std::lock_guard sl(recentLock_);
1925 
1926  insaneTime = insaneTime_;
1927  }
1928 
1929  bool reject = false;
1930 
1931  if (sanity_.load() == Sanity::insane)
1932  reject = (insaneTime - clock_type::now()) >
1933  std::chrono::seconds(Tuning::maxInsaneTime);
1934 
1935  if (sanity_.load() == Sanity::unknown)
1936  reject = (insaneTime - clock_type::now()) >
1937  std::chrono::seconds(Tuning::maxUnknownTime);
1938 
1939  if (reject)
1940  {
1941  overlay_.peerFinder().on_failure(slot_);
1942  post(
1943  strand_,
1944  std::bind(
1945  (void (PeerImp::*)(std::string const&)) & PeerImp::fail,
1946  shared_from_this(),
1947  "Not useful"));
1948  }
1949 }
1950 
1951 void
1953 {
1954  if (!stringIsUint256Sized(m->hash()))
1955  {
1956  fee_ = Resource::feeInvalidRequest;
1957  return;
1958  }
1959 
1960  uint256 const hash{m->hash()};
1961 
1962  if (m->status() == protocol::tsHAVE)
1963  {
1964  std::lock_guard sl(recentLock_);
1965 
1966  if (std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
1967  recentTxSets_.end())
1968  {
1969  fee_ = Resource::feeUnwantedData;
1970  return;
1971  }
1972 
1973  recentTxSets_.push_back(hash);
1974  }
1975 }
1976 
1977 void
1979 {
1980  try
1981  {
1982  if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
1983  {
1984  JLOG(p_journal_.debug())
1985  << "ValidatorList: received validator list from peer using "
1986  << "protocol version " << to_string(protocol_)
1987  << " which shouldn't support this feature.";
1988  fee_ = Resource::feeUnwantedData;
1989  return;
1990  }
1991  auto const& manifest = m->manifest();
1992  auto const& blob = m->blob();
1993  auto const& signature = m->signature();
1994  auto const version = m->version();
1995  auto const hash = sha512Half(manifest, blob, signature, version);
1996 
1997  JLOG(p_journal_.debug())
1998  << "Received validator list from " << remote_address_.to_string()
1999  << " (" << id_ << ")";
2000 
2001  if (!app_.getHashRouter().addSuppressionPeer(hash, id_))
2002  {
2003  JLOG(p_journal_.debug())
2004  << "ValidatorList: received duplicate validator list";
2005  // Charging this fee here won't hurt the peer in the normal
2006  // course of operation (ie. refresh every 5 minutes), but
2007  // will add up if the peer is misbehaving.
2008  fee_ = Resource::feeUnwantedData;
2009  return;
2010  }
2011 
2012  auto const applyResult = app_.validators().applyListAndBroadcast(
2013  manifest,
2014  blob,
2015  signature,
2016  version,
2017  remote_address_.to_string(),
2018  hash,
2019  app_.overlay(),
2020  app_.getHashRouter());
2021  auto const disp = applyResult.disposition;
2022 
2023  JLOG(p_journal_.debug())
2024  << "Processed validator list from "
2025  << (applyResult.publisherKey ? strHex(*applyResult.publisherKey)
2026  : "unknown or invalid publisher")
2027  << " from " << remote_address_.to_string() << " (" << id_
2028  << ") with result " << to_string(disp);
2029 
2030  switch (disp)
2031  {
2032  case ListDisposition::accepted:
2033  JLOG(p_journal_.debug())
2034  << "Applied new validator list from peer "
2035  << remote_address_;
2036  {
2037  std::lock_guard<std::mutex> sl(recentLock_);
2038 
2039  assert(applyResult.sequence && applyResult.publisherKey);
2040  auto const& pubKey = *applyResult.publisherKey;
2041 #ifndef NDEBUG
2042  if (auto const iter = publisherListSequences_.find(pubKey);
2043  iter != publisherListSequences_.end())
2044  {
2045  assert(iter->second < *applyResult.sequence);
2046  }
2047 #endif
2048  publisherListSequences_[pubKey] = *applyResult.sequence;
2049  }
2050  break;
2051  case ListDisposition::same_sequence:
2052  JLOG(p_journal_.warn())
2053  << "Validator list with current sequence from peer "
2054  << remote_address_;
2055  // Charging this fee here won't hurt the peer in the normal
2056  // course of operation (ie. refresh every 5 minutes), but
2057  // will add up if the peer is misbehaving.
2058  fee_ = Resource::feeUnwantedData;
2059 #ifndef NDEBUG
2060  {
2061  std::lock_guard<std::mutex> sl(recentLock_);
2062  assert(applyResult.sequence && applyResult.publisherKey);
2063  assert(
2064  publisherListSequences_[*applyResult.publisherKey] ==
2065  *applyResult.sequence);
2066  }
2067 #endif // !NDEBUG
2068 
2069  break;
2070  case ListDisposition::stale:
2071  JLOG(p_journal_.warn())
2072  << "Stale validator list from peer " << remote_address_;
2073  // There are very few good reasons for a peer to send an
2074  // old list, particularly more than once.
2075  fee_ = Resource::feeBadData;
2076  break;
2077  case ListDisposition::untrusted:
2078  JLOG(p_journal_.warn())
2079  << "Untrusted validator list from peer " << remote_address_;
2080  // Charging this fee here won't hurt the peer in the normal
2081  // course of operation (ie. refresh every 5 minutes), but
2082  // will add up if the peer is misbehaving.
2083  fee_ = Resource::feeUnwantedData;
2084  break;
2085  case ListDisposition::invalid:
2086  JLOG(p_journal_.warn())
2087  << "Invalid validator list from peer " << remote_address_;
2088  // This shouldn't ever happen with a well-behaved peer
2089  fee_ = Resource::feeInvalidSignature;
2090  break;
2091  case ListDisposition::unsupported_version:
2092  JLOG(p_journal_.warn())
2093  << "Unsupported version validator list from peer "
2094  << remote_address_;
2095  // During a version transition, this may be legitimate.
2096  // If it happens frequently, that's probably bad.
2097  fee_ = Resource::feeBadData;
2098  break;
2099  default:
2100  assert(false);
2101  }
2102  }
2103  catch (std::exception const& e)
2104  {
2105  JLOG(p_journal_.warn()) << "ValidatorList: Exception, " << e.what()
2106  << " from peer " << remote_address_;
2107  fee_ = Resource::feeBadData;
2108  }
2109 }
2110 
2111 void
2112 PeerImp::onMessage(std::shared_ptr<protocol::TMValidation> const& m)
2113 {
2114  auto const closeTime = app_.timeKeeper().closeTime();
2115 
2116  if (m->validation().size() < 50)
2117  {
2118  JLOG(p_journal_.warn()) << "Validation: Too small";
2119  fee_ = Resource::feeInvalidRequest;
2120  return;
2121  }
2122 
2123  try
2124  {
2126  {
2127  SerialIter sit(makeSlice(m->validation()));
2128  val = std::make_shared<STValidation>(
2129  std::ref(sit),
2130  [this](PublicKey const& pk) {
2131  return calcNodeID(
2132  app_.validatorManifests().getMasterKey(pk));
2133  },
2134  false);
2135  val->setSeen(closeTime);
2136  }
2137 
2138  if (!isCurrent(
2139  app_.getValidations().parms(),
2140  app_.timeKeeper().closeTime(),
2141  val->getSignTime(),
2142  val->getSeenTime()))
2143  {
2144  JLOG(p_journal_.trace()) << "Validation: Not current";
2145  fee_ = Resource::feeUnwantedData;
2146  return;
2147  }
2148 
2149  if (!app_.getHashRouter().addSuppressionPeer(
2150  sha512Half(makeSlice(m->validation())), id_))
2151  {
2152  JLOG(p_journal_.trace()) << "Validation: duplicate";
2153  return;
2154  }
2155 
2156  auto const isTrusted =
2157  app_.validators().trusted(val->getSignerPublic());
2158 
2159  if (!isTrusted && (sanity_.load() == Sanity::insane))
2160  {
2161  JLOG(p_journal_.debug())
2162  << "Validation: dropping untrusted from insane peer";
2163  }
2164  if (isTrusted || cluster() || !app_.getFeeTrack().isLoadedLocal())
2165  {
2166  std::weak_ptr<PeerImp> weak = shared_from_this();
2167  app_.getJobQueue().addJob(
2168  isTrusted ? jtVALIDATION_t : jtVALIDATION_ut,
2169  "recvValidation->checkValidation",
2170  [weak, val, m](Job&) {
2171  if (auto peer = weak.lock())
2172  peer->checkValidation(val, m);
2173  });
2174  }
2175  else
2176  {
2177  JLOG(p_journal_.debug()) << "Validation: Dropping UNTRUSTED (load)";
2178  }
2179  }
2180  catch (std::exception const& e)
2181  {
2182  JLOG(p_journal_.warn())
2183  << "Exception processing validation: " << e.what();
2184  fee_ = Resource::feeInvalidRequest;
2185  }
2186 }
2187 
2188 void
2190 {
2191  protocol::TMGetObjectByHash& packet = *m;
2192 
2193  if (packet.query())
2194  {
2195  // this is a query
2196  if (send_queue_.size() >= Tuning::dropSendQueue)
2197  {
2198  JLOG(p_journal_.debug()) << "GetObject: Large send queue";
2199  return;
2200  }
2201 
2202  if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2203  {
2204  doFetchPack(m);
2205  return;
2206  }
2207 
2208  fee_ = Resource::feeMediumBurdenPeer;
2209 
2210  protocol::TMGetObjectByHash reply;
2211 
2212  reply.set_query(false);
2213 
2214  if (packet.has_seq())
2215  reply.set_seq(packet.seq());
2216 
2217  reply.set_type(packet.type());
2218 
2219  if (packet.has_ledgerhash())
2220  {
2221  if (!stringIsUint256Sized(packet.ledgerhash()))
2222  {
2223  fee_ = Resource::feeInvalidRequest;
2224  return;
2225  }
2226 
2227  reply.set_ledgerhash(packet.ledgerhash());
2228  }
2229 
2230  // This is a very minimal implementation
2231  for (int i = 0; i < packet.objects_size(); ++i)
2232  {
2233  auto const& obj = packet.objects(i);
2234  if (obj.has_hash() && stringIsUint256Sized(obj.hash()))
2235  {
2236  uint256 const hash{obj.hash()};
2237  // VFALCO TODO Move this someplace more sensible so we dont
2238  // need to inject the NodeStore interfaces.
2239  std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2240  auto hObj{app_.getNodeStore().fetch(hash, seq)};
2241  if (!hObj)
2242  {
2243  if (auto shardStore = app_.getShardStore())
2244  {
2245  if (seq >= shardStore->earliestLedgerSeq())
2246  hObj = shardStore->fetch(hash, seq);
2247  }
2248  }
2249  if (hObj)
2250  {
2251  protocol::TMIndexedObject& newObj = *reply.add_objects();
2252  newObj.set_hash(hash.begin(), hash.size());
2253  newObj.set_data(
2254  &hObj->getData().front(), hObj->getData().size());
2255 
2256  if (obj.has_nodeid())
2257  newObj.set_index(obj.nodeid());
2258  if (obj.has_ledgerseq())
2259  newObj.set_ledgerseq(obj.ledgerseq());
2260 
2261  // VFALCO NOTE "seq" in the message is obsolete
2262  }
2263  }
2264  }
2265 
2266  JLOG(p_journal_.trace()) << "GetObj: " << reply.objects_size() << " of "
2267  << packet.objects_size();
2268  send(std::make_shared<Message>(reply, protocol::mtGET_OBJECTS));
2269  }
2270  else
2271  {
2272  // this is a reply
2273  std::uint32_t pLSeq = 0;
2274  bool pLDo = true;
2275  bool progress = false;
2276 
2277  for (int i = 0; i < packet.objects_size(); ++i)
2278  {
2279  const protocol::TMIndexedObject& obj = packet.objects(i);
2280 
2281  if (obj.has_hash() && stringIsUint256Sized(obj.hash()))
2282  {
2283  if (obj.has_ledgerseq())
2284  {
2285  if (obj.ledgerseq() != pLSeq)
2286  {
2287  if (pLDo && (pLSeq != 0))
2288  {
2289  JLOG(p_journal_.debug())
2290  << "GetObj: Full fetch pack for " << pLSeq;
2291  }
2292  pLSeq = obj.ledgerseq();
2293  pLDo = !app_.getLedgerMaster().haveLedger(pLSeq);
2294 
2295  if (!pLDo)
2296  {
2297  JLOG(p_journal_.debug())
2298  << "GetObj: Late fetch pack for " << pLSeq;
2299  }
2300  else
2301  progress = true;
2302  }
2303  }
2304 
2305  if (pLDo)
2306  {
2307  uint256 const hash{obj.hash()};
2308 
2309  app_.getLedgerMaster().addFetchPack(
2310  hash,
2311  std::make_shared<Blob>(
2312  obj.data().begin(), obj.data().end()));
2313  }
2314  }
2315  }
2316 
2317  if (pLDo && (pLSeq != 0))
2318  {
2319  JLOG(p_journal_.debug())
2320  << "GetObj: Partial fetch pack for " << pLSeq;
2321  }
2322  if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2323  app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2324  }
2325 }
2326 
2327 //--------------------------------------------------------------------------
2328 
2329 void
2330 PeerImp::addLedger(
2331  uint256 const& hash,
2332  std::lock_guard<std::mutex> const& lockedRecentLock)
2333 {
2334  // lockedRecentLock is passed as a reminder that recentLock_ must be
2335  // locked by the caller.
2336  (void)lockedRecentLock;
2337 
2338  if (std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
2339  recentLedgers_.end())
2340  return;
2341 
2342  recentLedgers_.push_back(hash);
2343 }
2344 
2345 void
2346 PeerImp::doFetchPack(const std::shared_ptr<protocol::TMGetObjectByHash>& packet)
2347 {
2348  // VFALCO TODO Invert this dependency using an observer and shared state
2349  // object. Don't queue fetch pack jobs if we're under load or we already
2350  // have some queued.
2351  if (app_.getFeeTrack().isLoadedLocal() ||
2352  (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2353  (app_.getJobQueue().getJobCount(jtPACK) > 10))
2354  {
2355  JLOG(p_journal_.info()) << "Too busy to make fetch pack";
2356  return;
2357  }
2358 
2359  if (!stringIsUint256Sized(packet->ledgerhash()))
2360  {
2361  JLOG(p_journal_.warn()) << "FetchPack hash size malformed";
2362  fee_ = Resource::feeInvalidRequest;
2363  return;
2364  }
2365 
2366  fee_ = Resource::feeHighBurdenPeer;
2367 
2368  uint256 const hash{packet->ledgerhash()};
2369 
2370  std::weak_ptr<PeerImp> weak = shared_from_this();
2371  auto elapsed = UptimeClock::now();
2372  auto const pap = &app_;
2373  app_.getJobQueue().addJob(
2374  jtPACK, "MakeFetchPack", [pap, weak, packet, hash, elapsed](Job&) {
2375  pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
2376  });
2377 }
2378 
2379 void
2380 PeerImp::checkTransaction(
2381  int flags,
2382  bool checkSignature,
2383  std::shared_ptr<STTx const> const& stx)
2384 {
2385  // VFALCO TODO Rewrite to not use exceptions
2386  try
2387  {
2388  // Expired?
2389  if (stx->isFieldPresent(sfLastLedgerSequence) &&
2390  (stx->getFieldU32(sfLastLedgerSequence) <
2391  app_.getLedgerMaster().getValidLedgerIndex()))
2392  {
2393  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2394  charge(Resource::feeUnwantedData);
2395  return;
2396  }
2397 
2398  if (checkSignature)
2399  {
2400  // Check the signature before handing off to the job queue.
2401  if (auto [valid, validReason] = checkValidity(
2402  app_.getHashRouter(),
2403  *stx,
2404  app_.getLedgerMaster().getValidatedRules(),
2405  app_.config());
2406  valid != Validity::Valid)
2407  {
2408  if (!validReason.empty())
2409  {
2410  JLOG(p_journal_.trace())
2411  << "Exception checking transaction: " << validReason;
2412  }
2413 
2414  // Probably not necessary to set SF_BAD, but doesn't hurt.
2415  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2416  charge(Resource::feeInvalidSignature);
2417  return;
2418  }
2419  }
2420  else
2421  {
2422  forceValidity(
2423  app_.getHashRouter(), stx->getTransactionID(), Validity::Valid);
2424  }
2425 
2426  std::string reason;
2427  auto tx = std::make_shared<Transaction>(stx, reason, app_);
2428 
2429  if (tx->getStatus() == INVALID)
2430  {
2431  if (!reason.empty())
2432  {
2433  JLOG(p_journal_.trace())
2434  << "Exception checking transaction: " << reason;
2435  }
2436  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2437  charge(Resource::feeInvalidSignature);
2438  return;
2439  }
2440 
2441  bool const trusted(flags & SF_TRUSTED);
2442  app_.getOPs().processTransaction(
2443  tx, trusted, false, NetworkOPs::FailHard::no);
2444  }
2445  catch (std::exception const&)
2446  {
2447  app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2448  charge(Resource::feeBadData);
2449  }
2450 }
2451 
2452 // Called from our JobQueue
2453 void
2454 PeerImp::checkPropose(
2455  Job& job,
2457  RCLCxPeerPos peerPos)
2458 {
2459  bool isTrusted = (job.getType() == jtPROPOSAL_t);
2460 
2461  JLOG(p_journal_.trace())
2462  << "Checking " << (isTrusted ? "trusted" : "UNTRUSTED") << " proposal";
2463 
2464  assert(packet);
2465 
2466  if (!cluster() && !peerPos.checkSign())
2467  {
2468  JLOG(p_journal_.warn()) << "Proposal fails sig check";
2469  charge(Resource::feeInvalidSignature);
2470  return;
2471  }
2472 
2473  bool relay;
2474 
2475  if (isTrusted)
2476  relay = app_.getOPs().processTrustedProposal(peerPos);
2477  else
2478  relay = app_.config().RELAY_UNTRUSTED_PROPOSALS || cluster();
2479 
2480  if (relay)
2481  app_.overlay().relay(*packet, peerPos.suppressionID());
2482 }
2483 
2484 void
2485 PeerImp::checkValidation(
2486  std::shared_ptr<STValidation> const& val,
2488 {
2489  try
2490  {
2491  // VFALCO Which functions throw?
2492  if (!cluster() && !val->isValid())
2493  {
2494  JLOG(p_journal_.warn()) << "Validation is invalid";
2495  charge(Resource::feeInvalidRequest);
2496  return;
2497  }
2498 
2499  if (app_.getOPs().recvValidation(val, std::to_string(id())) ||
2500  cluster())
2501  {
2502  auto const suppression =
2503  sha512Half(makeSlice(val->getSerialized()));
2504  overlay_.relay(*packet, suppression);
2505  }
2506  }
2507  catch (std::exception const&)
2508  {
2509  JLOG(p_journal_.trace()) << "Exception processing validation";
2510  charge(Resource::feeInvalidRequest);
2511  }
2512 }
2513 
2514 // Returns the set of peers that can help us get
2515 // the TX tree with the specified root hash.
2516 //
2518 getPeerWithTree(OverlayImpl& ov, uint256 const& rootHash, PeerImp const* skip)
2519 {
2521  int retScore = 0;
2522 
2523  ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
2524  if (p->hasTxSet(rootHash) && p.get() != skip)
2525  {
2526  auto score = p->getScore(true);
2527  if (!ret || (score > retScore))
2528  {
2529  ret = std::move(p);
2530  retScore = score;
2531  }
2532  }
2533  });
2534 
2535  return ret;
2536 }
2537 
2538 // Returns a random peer weighted by how likely to
2539 // have the ledger and how responsive it is.
2540 //
2543  OverlayImpl& ov,
2544  uint256 const& ledgerHash,
2545  LedgerIndex ledger,
2546  PeerImp const* skip)
2547 {
2549  int retScore = 0;
2550 
2551  ov.for_each([&](std::shared_ptr<PeerImp>&& p) {
2552  if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
2553  {
2554  auto score = p->getScore(true);
2555  if (!ret || (score > retScore))
2556  {
2557  ret = std::move(p);
2558  retScore = score;
2559  }
2560  }
2561  });
2562 
2563  return ret;
2564 }
2565 
2566 // VFALCO NOTE This function is way too big and cumbersome.
2567 void
2568 PeerImp::getLedger(std::shared_ptr<protocol::TMGetLedger> const& m)
2569 {
2570  protocol::TMGetLedger& packet = *m;
2571  std::shared_ptr<SHAMap> shared;
2572  SHAMap const* map = nullptr;
2573  protocol::TMLedgerData reply;
2574  bool fatLeaves = true;
2576 
2577  if (packet.has_requestcookie())
2578  reply.set_requestcookie(packet.requestcookie());
2579 
2580  std::string logMe;
2581 
2582  if (packet.itype() == protocol::liTS_CANDIDATE)
2583  {
2584  // Request is for a transaction candidate set
2585  JLOG(p_journal_.trace()) << "GetLedger: Tx candidate set";
2586 
2587  if (!packet.has_ledgerhash() ||
2588  !stringIsUint256Sized(packet.ledgerhash()))
2589  {
2590  charge(Resource::feeInvalidRequest);
2591  JLOG(p_journal_.warn()) << "GetLedger: Tx candidate set invalid";
2592  return;
2593  }
2594 
2595  uint256 const txHash{packet.ledgerhash()};
2596 
2597  shared = app_.getInboundTransactions().getSet(txHash, false);
2598  map = shared.get();
2599 
2600  if (!map)
2601  {
2602  if (packet.has_querytype() && !packet.has_requestcookie())
2603  {
2604  JLOG(p_journal_.debug()) << "GetLedger: Routing Tx set request";
2605 
2606  if (auto const v = getPeerWithTree(overlay_, txHash, this))
2607  {
2608  packet.set_requestcookie(id());
2609  v->send(std::make_shared<Message>(
2610  packet, protocol::mtGET_LEDGER));
2611  return;
2612  }
2613 
2614  JLOG(p_journal_.info()) << "GetLedger: Route TX set failed";
2615  return;
2616  }
2617 
2618  JLOG(p_journal_.debug()) << "GetLedger: Can't provide map ";
2619  charge(Resource::feeInvalidRequest);
2620  return;
2621  }
2622 
2623  reply.set_ledgerseq(0);
2624  reply.set_ledgerhash(txHash.begin(), txHash.size());
2625  reply.set_type(protocol::liTS_CANDIDATE);
2626  fatLeaves = false; // We'll already have most transactions
2627  }
2628  else
2629  {
2630  if (send_queue_.size() >= Tuning::dropSendQueue)
2631  {
2632  JLOG(p_journal_.debug()) << "GetLedger: Large send queue";
2633  return;
2634  }
2635 
2636  if (app_.getFeeTrack().isLoadedLocal() && !cluster())
2637  {
2638  JLOG(p_journal_.debug()) << "GetLedger: Too busy";
2639  return;
2640  }
2641 
2642  // Figure out what ledger they want
2643  JLOG(p_journal_.trace()) << "GetLedger: Received";
2644 
2645  if (packet.has_ledgerhash())
2646  {
2647  if (!stringIsUint256Sized(packet.ledgerhash()))
2648  {
2649  charge(Resource::feeInvalidRequest);
2650  JLOG(p_journal_.warn()) << "GetLedger: Invalid request";
2651  return;
2652  }
2653 
2654  uint256 const ledgerhash{packet.ledgerhash()};
2655  logMe += "LedgerHash:";
2656  logMe += to_string(ledgerhash);
2657  ledger = app_.getLedgerMaster().getLedgerByHash(ledgerhash);
2658 
2659  if (!ledger && packet.has_ledgerseq())
2660  {
2661  if (auto shardStore = app_.getShardStore())
2662  {
2663  auto seq = packet.ledgerseq();
2664  if (seq >= shardStore->earliestLedgerSeq())
2665  ledger = shardStore->fetchLedger(ledgerhash, seq);
2666  }
2667  }
2668 
2669  if (!ledger)
2670  {
2671  JLOG(p_journal_.trace())
2672  << "GetLedger: Don't have " << ledgerhash;
2673  }
2674 
2675  if (!ledger &&
2676  (packet.has_querytype() && !packet.has_requestcookie()))
2677  {
2678  // We don't have the requested ledger
2679  // Search for a peer who might
2680  auto const v = getPeerWithLedger(
2681  overlay_,
2682  ledgerhash,
2683  packet.has_ledgerseq() ? packet.ledgerseq() : 0,
2684  this);
2685  if (!v)
2686  {
2687  JLOG(p_journal_.trace()) << "GetLedger: Cannot route";
2688  return;
2689  }
2690 
2691  packet.set_requestcookie(id());
2692  v->send(
2693  std::make_shared<Message>(packet, protocol::mtGET_LEDGER));
2694  JLOG(p_journal_.debug()) << "GetLedger: Request routed";
2695  return;
2696  }
2697  }
2698  else if (packet.has_ledgerseq())
2699  {
2700  if (packet.ledgerseq() < app_.getLedgerMaster().getEarliestFetch())
2701  {
2702  JLOG(p_journal_.debug()) << "GetLedger: Early ledger request";
2703  return;
2704  }
2705  ledger = app_.getLedgerMaster().getLedgerBySeq(packet.ledgerseq());
2706  if (!ledger)
2707  {
2708  JLOG(p_journal_.debug())
2709  << "GetLedger: Don't have " << packet.ledgerseq();
2710  }
2711  }
2712  else if (packet.has_ltype() && (packet.ltype() == protocol::ltCLOSED))
2713  {
2714  ledger = app_.getLedgerMaster().getClosedLedger();
2715  assert(!ledger->open());
2716  // VFALCO ledger should never be null!
2717  // VFALCO How can the closed ledger be open?
2718 #if 0
2719  if (ledger && ledger->info().open)
2720  ledger = app_.getLedgerMaster ().getLedgerBySeq (
2721  ledger->info().seq - 1);
2722 #endif
2723  }
2724  else
2725  {
2726  charge(Resource::feeInvalidRequest);
2727  JLOG(p_journal_.warn()) << "GetLedger: Unknown request";
2728  return;
2729  }
2730 
2731  if ((!ledger) ||
2732  (packet.has_ledgerseq() &&
2733  (packet.ledgerseq() != ledger->info().seq)))
2734  {
2735  charge(Resource::feeInvalidRequest);
2736 
2737  if (ledger)
2738  {
2739  JLOG(p_journal_.warn()) << "GetLedger: Invalid sequence";
2740  }
2741  return;
2742  }
2743 
2744  if (!packet.has_ledgerseq() &&
2745  (ledger->info().seq < app_.getLedgerMaster().getEarliestFetch()))
2746  {
2747  JLOG(p_journal_.debug()) << "GetLedger: Early ledger request";
2748  return;
2749  }
2750 
2751  // Fill out the reply
2752  auto const lHash = ledger->info().hash;
2753  reply.set_ledgerhash(lHash.begin(), lHash.size());
2754  reply.set_ledgerseq(ledger->info().seq);
2755  reply.set_type(packet.itype());
2756 
2757  if (packet.itype() == protocol::liBASE)
2758  {
2759  // they want the ledger base data
2760  JLOG(p_journal_.trace()) << "GetLedger: Base data";
2761  Serializer nData(128);
2762  addRaw(ledger->info(), nData);
2763  reply.add_nodes()->set_nodedata(
2764  nData.getDataPtr(), nData.getLength());
2765 
2766  auto const& stateMap = ledger->stateMap();
2767  if (stateMap.getHash() != beast::zero)
2768  {
2769  // return account state root node if possible
2770  Serializer rootNode(768);
2771  if (stateMap.getRootNode(rootNode, snfWIRE))
2772  {
2773  reply.add_nodes()->set_nodedata(
2774  rootNode.getDataPtr(), rootNode.getLength());
2775 
2776  if (ledger->info().txHash != beast::zero)
2777  {
2778  auto const& txMap = ledger->txMap();
2779 
2780  if (txMap.getHash() != beast::zero)
2781  {
2782  rootNode.erase();
2783 
2784  if (txMap.getRootNode(rootNode, snfWIRE))
2785  reply.add_nodes()->set_nodedata(
2786  rootNode.getDataPtr(),
2787  rootNode.getLength());
2788  }
2789  }
2790  }
2791  }
2792 
2793  auto oPacket =
2794  std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
2795  send(oPacket);
2796  return;
2797  }
2798 
2799  if (packet.itype() == protocol::liTX_NODE)
2800  {
2801  map = &ledger->txMap();
2802  logMe += " TX:";
2803  logMe += to_string(map->getHash());
2804  }
2805  else if (packet.itype() == protocol::liAS_NODE)
2806  {
2807  map = &ledger->stateMap();
2808  logMe += " AS:";
2809  logMe += to_string(map->getHash());
2810  }
2811  }
2812 
2813  if (!map || (packet.nodeids_size() == 0))
2814  {
2815  JLOG(p_journal_.warn()) << "GetLedger: Can't find map or empty request";
2816  charge(Resource::feeInvalidRequest);
2817  return;
2818  }
2819 
2820  JLOG(p_journal_.trace()) << "GetLedger: " << logMe;
2821 
2822  auto const depth = packet.has_querydepth()
2823  ? (std::min(packet.querydepth(), 3u))
2824  : (isHighLatency() ? 2 : 1);
2825 
2826  for (int i = 0;
2827  (i < packet.nodeids().size() &&
2828  (reply.nodes().size() < Tuning::maxReplyNodes));
2829  ++i)
2830  {
2831  SHAMapNodeID mn(packet.nodeids(i).data(), packet.nodeids(i).size());
2832 
2833  if (!mn.isValid())
2834  {
2835  JLOG(p_journal_.warn()) << "GetLedger: Invalid node " << logMe;
2836  charge(Resource::feeInvalidRequest);
2837  return;
2838  }
2839 
2840  std::vector<SHAMapNodeID> nodeIDs;
2841  std::vector<Blob> rawNodes;
2842 
2843  try
2844  {
2845  if (map->getNodeFat(mn, nodeIDs, rawNodes, fatLeaves, depth))
2846  {
2847  assert(nodeIDs.size() == rawNodes.size());
2848  JLOG(p_journal_.trace()) << "GetLedger: getNodeFat got "
2849  << rawNodes.size() << " nodes";
2850  std::vector<SHAMapNodeID>::iterator nodeIDIterator;
2851  std::vector<Blob>::iterator rawNodeIterator;
2852 
2853  for (nodeIDIterator = nodeIDs.begin(),
2854  rawNodeIterator = rawNodes.begin();
2855  nodeIDIterator != nodeIDs.end();
2856  ++nodeIDIterator, ++rawNodeIterator)
2857  {
2858  Serializer nID(33);
2859  nodeIDIterator->addIDRaw(nID);
2860  protocol::TMLedgerNode* node = reply.add_nodes();
2861  node->set_nodeid(nID.getDataPtr(), nID.getLength());
2862  node->set_nodedata(
2863  &rawNodeIterator->front(), rawNodeIterator->size());
2864  }
2865  }
2866  else
2867  {
2868  JLOG(p_journal_.warn())
2869  << "GetLedger: getNodeFat returns false";
2870  }
2871  }
2872  catch (std::exception&)
2873  {
2874  std::string info;
2875 
2876  if (packet.itype() == protocol::liTS_CANDIDATE)
2877  info = "TS candidate";
2878  else if (packet.itype() == protocol::liBASE)
2879  info = "Ledger base";
2880  else if (packet.itype() == protocol::liTX_NODE)
2881  info = "TX node";
2882  else if (packet.itype() == protocol::liAS_NODE)
2883  info = "AS node";
2884 
2885  if (!packet.has_ledgerhash())
2886  info += ", no hash specified";
2887 
2888  JLOG(p_journal_.warn())
2889  << "getNodeFat( " << mn << ") throws exception: " << info;
2890  }
2891  }
2892 
2893  JLOG(p_journal_.info())
2894  << "Got request for " << packet.nodeids().size() << " nodes at depth "
2895  << depth << ", return " << reply.nodes().size() << " nodes";
2896 
2897  auto oPacket = std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
2898  send(oPacket);
2899 }
2900 
2901 int
2902 PeerImp::getScore(bool haveItem) const
2903 {
2904  // Random component of score, used to break ties and avoid
2905  // overloading the "best" peer
2906  static const int spRandomMax = 9999;
2907 
2908  // Score for being very likely to have the thing we are
2909  // look for; should be roughly spRandomMax
2910  static const int spHaveItem = 10000;
2911 
2912  // Score reduction for each millisecond of latency; should
2913  // be roughly spRandomMax divided by the maximum reasonable
2914  // latency
2915  static const int spLatency = 30;
2916 
2917  // Penalty for unknown latency; should be roughly spRandomMax
2918  static const int spNoLatency = 8000;
2919 
2920  int score = rand_int(spRandomMax);
2921 
2922  if (haveItem)
2923  score += spHaveItem;
2924 
2925  boost::optional<std::chrono::milliseconds> latency;
2926  {
2927  std::lock_guard sl(recentLock_);
2928  latency = latency_;
2929  }
2930 
2931  if (latency)
2932  score -= latency->count() * spLatency;
2933  else
2934  score -= spNoLatency;
2935 
2936  return score;
2937 }
2938 
2939 bool
2940 PeerImp::isHighLatency() const
2941 {
2942  std::lock_guard sl(recentLock_);
2943  return latency_ >= Tuning::peerHighLatency;
2944 }
2945 
2946 void
2947 PeerImp::Metrics::add_message(std::uint64_t bytes)
2948 {
2949  using namespace std::chrono_literals;
2950  std::unique_lock lock{mutex_};
2951 
2952  totalBytes_ += bytes;
2953  accumBytes_ += bytes;
2954  auto const timeElapsed = clock_type::now() - intervalStart_;
2955  auto const timeElapsedInSecs =
2956  std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
2957 
2958  if (timeElapsedInSecs >= 1s)
2959  {
2960  auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
2961  rollingAvg_.push_back(avgBytes);
2962 
2963  auto const totalBytes =
2964  std::accumulate(rollingAvg_.begin(), rollingAvg_.end(), 0ull);
2965  rollingAvgBytes_ = totalBytes / rollingAvg_.size();
2966 
2967  intervalStart_ = clock_type::now();
2968  accumBytes_ = 0;
2969  }
2970 }
2971 
2973 PeerImp::Metrics::average_bytes() const
2974 {
2975  std::shared_lock lock{mutex_};
2976  return rollingAvgBytes_;
2977 }
2978 
2980 PeerImp::Metrics::total_bytes() const
2981 {
2982  std::shared_lock lock{mutex_};
2983  return totalBytes_;
2984 }
2985 
2986 } // namespace ripple
ripple::PublicKey::data
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:81
ripple::PeerImp::ledgerRange
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
Definition: PeerImp.cpp:455
ripple::PeerImp::uptime
clock_type::duration uptime() const
Definition: PeerImp.h:354
ripple::OverlayImpl::findPeerByShortID
std::shared_ptr< Peer > findPeerByShortID(Peer::id_t const &id) override
Returns the peer with the matching short id, or null.
Definition: OverlayImpl.cpp:1219
ripple::Resource::feeInvalidRequest
const Charge feeInvalidRequest
Schedule of fees charged for imposing load on the server.
ripple::Application
Definition: Application.h:97
ripple::ClusterNode
Definition: ClusterNode.h:30
ripple::jtTRANSACTION
@ jtTRANSACTION
Definition: Job.h:51
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::Tuning::sendQueueLogFreq
@ sendQueueLogFreq
How often to log send queue size.
Definition: overlay/impl/Tuning.h:73
ripple::PeerImp::recentLock_
std::mutex recentLock_
Definition: PeerImp.h:175
ripple::RCLCxPeerPos
A peer's signed, proposed position for use in RCLConsensus.
Definition: RCLCxPeerPos.h:42
std::weak_ptr::lock
T lock(T... args)
ripple::PeerImp::Sanity::unknown
@ unknown
ripple::PeerImp::stream_ptr_
std::unique_ptr< stream_type > stream_ptr_
Definition: PeerImp.h:101
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
ripple::PeerImp::onMessageBegin
void onMessageBegin(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m, std::size_t size)
Definition: PeerImp.cpp:1001
ripple::csHopLimit
static constexpr std::uint32_t csHopLimit
Definition: ripple/overlay/Peer.h:36
ripple::Application::cluster
virtual Cluster & cluster()=0
ripple::PeerImp::socket_
socket_type & socket_
Definition: PeerImp.h:102
std::bind
T bind(T... args)
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::PeerImp::onMessage
void onMessage(std::shared_ptr< protocol::TMManifests > const &m)
Definition: PeerImp.cpp:1023
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: app/misc/impl/Manifest.cpp:301
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:793
ripple::PeerImp::checkSanity
void checkSanity(std::uint32_t validationSeq)
Check if the peer is sane.
Definition: PeerImp.cpp:1874
std::exception
STL class.
ripple::PeerImp::hasTxSet
bool hasTxSet(uint256 const &hash) const override
Definition: PeerImp.cpp:474
ripple::calcNodeID
NodeID calcNodeID(PublicKey const &pk)
Calculate the 160-bit node ID from a node public key.
Definition: PublicKey.cpp:299
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::publicKeyType
boost::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:203
ripple::PeerImp::strand_
boost::asio::strand< boost::asio::executor > strand_
Definition: PeerImp.h:104
ripple::Tuning::targetSendQueue
@ targetSendQueue
How many messages we consider reasonable sustained on a send queue.
Definition: overlay/impl/Tuning.h:70
ripple::PeerImp::recentLedgers_
boost::circular_buffer< uint256 > recentLedgers_
Definition: PeerImp.h:137
ripple::PeerImp::request_
http_request_type request_
Definition: PeerImp.h:181
ripple::Resource::Gossip
Data format for exchanging consumption information across peers.
Definition: Gossip.h:29
ripple::Manifest
Definition: Manifest.h:78
ripple::PeerImp::~PeerImp
virtual ~PeerImp()
Definition: PeerImp.cpp:99
ripple::PeerImp::getShardIndexes
boost::optional< RangeSet< std::uint32_t > > getShardIndexes() const
Return a range set of known shard indexes from this peer.
Definition: PeerImp.cpp:557
ripple::Serializer::erase
void erase()
Definition: Serializer.h:207
beast::IP::Endpoint::to_string
std::string to_string() const
Returns a string representing the endpoint.
Definition: IPEndpoint.cpp:54
std::pair
ripple::http_request_type
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition: Handoff.h:31
ripple::PeerImp::doAccept
void doAccept()
Definition: PeerImp.cpp:718
std::vector::reserve
T reserve(T... args)
ripple::HashRouter::shouldProcess
bool shouldProcess(uint256 const &key, PeerShortID peer, int &flags, std::chrono::seconds tx_interval)
Definition: HashRouter.cpp:72
ripple::HashPrefix::manifest
@ manifest
Manifest.
ripple::PeerImp::metrics_
struct ripple::PeerImp::@14 metrics_
ripple::SHAMap::getNodeFat
bool getNodeFat(SHAMapNodeID node, std::vector< SHAMapNodeID > &nodeIDs, std::vector< Blob > &rawNode, bool fatLeaves, std::uint32_t depth) const
Definition: SHAMapSync.cpp:447
ripple::LedgerMaster::getValidLedgerIndex
LedgerIndex getValidLedgerIndex()
Definition: LedgerMaster.cpp:212
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
ripple::PeerImp::doProtocolStart
void doProtocolStart()
Definition: PeerImp.cpp:835
std::vector
STL class.
std::find
T find(T... args)
std::string::size
T size(T... args)
ripple::PeerImp::write_buffer_
boost::beast::multi_buffer write_buffer_
Definition: PeerImp.h:184
ripple::PeerImp::recentTxSets_
boost::circular_buffer< uint256 > recentTxSets_
Definition: PeerImp.h:138
ripple::PublicKey::empty
bool empty() const noexcept
Definition: PublicKey.h:117
ripple::Tuning::sendqIntervals
@ sendqIntervals
How many timer intervals a sendq has to stay large before we disconnect.
Definition: overlay/impl/Tuning.h:61
ripple::make_protocol
constexpr ProtocolVersion make_protocol(std::uint16_t major, std::uint16_t minor)
Definition: ProtocolVersion.h:40
std::chrono::seconds
ripple::PeerImp::setTimer
void setTimer()
Definition: PeerImp.cpp:597
ripple::PeerImp::no_ping_
int no_ping_
Definition: PeerImp.h:188
ripple::OverlayImpl::incPeerDisconnectCharges
void incPeerDisconnectCharges() override
Definition: OverlayImpl.h:340
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::SHAMapNodeID::isValid
bool isValid() const
Definition: SHAMapNodeID.h:118
beast::IP::Endpoint::address
Address const & address() const
Returns the address portion of this endpoint.
Definition: IPEndpoint.h:77
ripple::PeerImp::getVersion
std::string getVersion() const
Return the version of rippled that the peer is running, if reported.
Definition: PeerImp.cpp:301
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::Tuning::noPing
@ noPing
How many timer intervals we can go without a ping reply.
Definition: overlay/impl/Tuning.h:64
ripple::SBoxCmp::diff
@ diff
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
ripple::PeerImp::close
void close()
Definition: PeerImp.cpp:502
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:272
ripple::match_peer
Select the specific peer.
Definition: predicates.h:115
ripple::PeerImp::onMessageUnknown
void onMessageUnknown(std::uint16_t type)
Definition: PeerImp.cpp:995
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s)
Definition: View.cpp:43
ripple::from_string
bool from_string(RangeSet< T > &rs, std::string const &s)
Convert the given styled string to a RangeSet.
Definition: RangeSet.h:126
ripple::JobQueue::addJob
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Definition: JobQueue.h:166
std::setfill
T setfill(T... args)
std::vector::back
T back(T... args)
ripple::PeerImp::ShardInfo::endpoint
beast::IP::Endpoint endpoint
Definition: PeerImp.h:77
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
ripple::PeerImp::journal_
const beast::Journal journal_
Definition: PeerImp.h:99
ripple::SHAMapNodeID
Definition: SHAMapNodeID.h:33
ripple::PeerImp::send
void send(std::shared_ptr< Message > const &m) override
Definition: PeerImp.cpp:220
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
ripple::buildHandshake
void buildHandshake(boost::beast::http::fields &h, ripple::uint256 const &sharedValue, boost::optional< std::uint32_t > networkID, beast::IP::Address public_ip, beast::IP::Address remote_ip, Application &app)
Insert fields headers necessary for upgrading the link to the peer protocol.
Definition: Handshake.cpp:102
ripple::OverlayImpl::setup
Setup const & setup() const
Definition: OverlayImpl.h:166
ripple::ProtocolFeature
ProtocolFeature
Definition: ripple/overlay/Peer.h:38
ripple::PeerImp::onTimer
void onTimer(boost::system::error_code const &ec)
Definition: PeerImp.cpp:632
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:142
ripple::PeerImp::Sanity::sane
@ sane
ripple::OverlayImpl::incJqTransOverflow
void incJqTransOverflow() override
Increment and retrieve counter for transaction job queue overflows.
Definition: OverlayImpl.h:316
ripple::PeerImp
Definition: PeerImp.h:45
ripple::PeerFinder::Config::peerPrivate
bool peerPrivate
true if we want our IP address kept private.
Definition: PeerfinderManager.h:61
ripple::PeerImp::previousLedgerHash_
uint256 previousLedgerHash_
Definition: PeerImp.h:135
std::vector::front
T front(T... args)
algorithm
ripple::Application::getOPs
virtual NetworkOPs & getOPs()=0
ripple::PeerImp::name_
std::string name_
Definition: PeerImp.h:127
ripple::PeerImp::sanity_
std::atomic< Sanity > sanity_
Definition: PeerImp.h:122
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::PeerImp::nameMutex_
std::shared_timed_mutex nameMutex_
Definition: PeerImp.h:128
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:462
ripple::Tuning::timerSeconds
@ timerSeconds
How often we latency/sendq probe connections.
Definition: overlay/impl/Tuning.h:57
ripple::getPeerWithLedger
static std::shared_ptr< PeerImp > getPeerWithLedger(OverlayImpl &ov, uint256 const &ledgerHash, LedgerIndex ledger, PeerImp const *skip)
Definition: PeerImp.cpp:2542
ripple::PeerImp::publicKey_
const PublicKey publicKey_
Definition: PeerImp.h:126
ripple::protocolMessageName
std::string protocolMessageName(int type)
Returns the name of a protocol message given its type.
Definition: ProtocolMessage.h:42
ripple::PeerImp::read_buffer_
boost::beast::multi_buffer read_buffer_
Definition: PeerImp.h:180
ripple::PeerImp::error_code
boost::system::error_code error_code
Definition: PeerImp.h:85
ripple::JobQueue::getJobCount
int getJobCount(JobType t) const
Jobs waiting at this priority.
Definition: JobQueue.cpp:121
std::tie
T tie(T... args)
std::vector::push_back
T push_back(T... args)
ripple::PeerImp::remote_address_
const beast::IP::Endpoint remote_address_
Definition: PeerImp.h:111
ripple::Cluster::member
boost::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
Definition: Cluster.cpp:39
ripple::jtTXN_DATA
@ jtTXN_DATA
Definition: Job.h:55
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:148
ripple::getPeerWithTree
static std::shared_ptr< PeerImp > getPeerWithTree(OverlayImpl &ov, uint256 const &rootHash, PeerImp const *skip)
Definition: PeerImp.cpp:2518
ripple::base_uint< 256 >
ripple::sfLastLedgerSequence
const SF_U32 sfLastLedgerSequence(access, STI_UINT32, 27, "LastLedgerSequence")
Definition: SField.h:380
ripple::LoadFeeTrack::isLoadedLocal
bool isLoadedLocal() const
Definition: LoadFeeTrack.h:123
ripple::PeerImp::addLedger
void addLedger(uint256 const &hash, std::lock_guard< std::mutex > const &lockedRecentLock)
Definition: PeerImp.cpp:2330
ripple::http_response_type
boost::beast::http::response< boost::beast::http::dynamic_body > http_response_type
Definition: Handoff.h:34
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:682
ripple::Overlay::Setup::public_ip
beast::IP::Address public_ip
Definition: Overlay.h:75
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::PeerImp::state_
State state_
Definition: PeerImp.h:121
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:60
ripple::base_uint::isZero
bool isZero() const
Definition: base_uint.h:475
ripple::OverlayImpl::resourceManager
Resource::Manager & resourceManager()
Definition: OverlayImpl.h:154
beast::IP::Address
boost::asio::ip::address Address
Definition: IPAddress.h:41
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::PeerImp::gracefulClose
void gracefulClose()
Definition: PeerImp.cpp:576
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::PeerImp::shardInfo_
hash_map< PublicKey, ShardInfo > shardInfo_
Definition: PeerImp.h:195
ripple::Serializer::getDataPtr
const void * getDataPtr() const
Definition: Serializer.h:187
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:134
ripple::PeerImp::lastPingSeq_
boost::optional< std::uint32_t > lastPingSeq_
Definition: PeerImp.h:141
ripple::PeerImp::detaching_
bool detaching_
Definition: PeerImp.h:124
ripple::PeerImp::onMessageEnd
void onMessageEnd(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m)
Definition: PeerImp.cpp:1014
ripple::Application::config
virtual Config & config()=0
ripple::PeerImp::onWriteResponse
void onWriteResponse(error_code ec, std::size_t bytes_transferred)
Definition: PeerImp.cpp:792
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:145
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::NodeStore::seqToShardIndex
constexpr std::uint32_t seqToShardIndex(std::uint32_t seq, std::uint32_t ledgersPerShard=DatabaseShard::ledgersPerShardDefault)
Definition: DatabaseShard.h:190
ripple::PeerImp::stream_
stream_type & stream_
Definition: PeerImp.h:103
ripple::PeerImp::onWriteMessage
void onWriteMessage(error_code ec, std::size_t bytes_transferred)
Definition: PeerImp.cpp:941
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:81
ripple::InfoSub::Source::pubPeerStatus
virtual void pubPeerStatus(std::function< Json::Value(void)> const &)=0
ripple::jtVALIDATION_t
@ jtVALIDATION_t
Definition: Job.h:57
ripple::PeerImp::hasRange
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
Definition: PeerImp.cpp:492
ripple::Resource::feeUnwantedData
const Charge feeUnwantedData
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:482
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:276
ripple::PeerImp::app_
Application & app_
Definition: PeerImp.h:95
ripple::PeerImp::crawl
bool crawl() const
Returns true if this connection will publicly share its IP address.
Definition: PeerImp.cpp:286
ripple::PeerImp::minLedger_
LedgerIndex minLedger_
Definition: PeerImp.h:132
ripple::makeSharedValue
boost::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
Definition: Handshake.cpp:70
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::PeerImp::hasLedger
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
Definition: PeerImp.cpp:438
ripple::Resource::Consumer::balance
int balance()
Returns the credit balance representing consumption.
Definition: Consumer.cpp:124
ripple::HashPrefix::proposal
@ proposal
proposal for signing
ripple::ManifestCache::for_each_manifest
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition: Manifest.h:369
ripple::TimeKeeper::closeTime
virtual time_point closeTime() const =0
Returns the close time, in network time.
ripple::Job
Definition: Job.h:82
ripple::PeerImp::headers_
boost::beast::http::fields const & headers_
Definition: PeerImp.h:183
std::accumulate
T accumulate(T... args)
ripple::SerialIter
Definition: Serializer.h:308
ripple::PeerImp::Sanity::insane
@ insane
std::uint32_t
ripple::PeerImp::send_queue_
std::queue< std::shared_ptr< Message > > send_queue_
Definition: PeerImp.h:185
ripple::NodeStore::Database::earliestLedgerSeq
std::uint32_t earliestLedgerSeq() const
Definition: Database.h:236
ripple::PeerImp::slot_
const std::shared_ptr< PeerFinder::Slot > slot_
Definition: PeerImp.h:179
ripple::Overlay::foreach
void foreach(Function f) const
Visit every active peer.
Definition: Overlay.h:167
ripple::PeerImp::load_event_
std::unique_ptr< LoadEvent > load_event_
Definition: PeerImp.h:189
ripple::PeerImp::protocol_
ProtocolVersion protocol_
Definition: PeerImp.h:119
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
ripple::PeerImp::State::active
@ active
ripple::base_uint::SetHexExact
bool SetHexExact(const char *psz)
Parse a hex string into a base_uint The string must contain exactly bytes * 2 hex characters and must...
Definition: base_uint.h:370
std::nth_element
T nth_element(T... args)
memory
ripple::PeerImp::m_inbound
const bool m_inbound
Definition: PeerImp.h:116
ripple::PeerImp::waitable_timer
boost::asio::basic_waitable_timer< std::chrono::steady_clock > waitable_timer
Definition: PeerImp.h:92
ripple::jtPEER
@ jtPEER
Definition: Job.h:67
ripple::PeerImp::onShutdown
void onShutdown(error_code ec)
Definition: PeerImp.cpp:701
ripple::proposalUniqueId
uint256 proposalUniqueId(uint256 const &proposeHash, uint256 const &previousLedger, std::uint32_t proposeSeq, NetClock::time_point closeTime, Slice const &publicKey, Slice const &signature)
Calculate a unique identifier for a signed proposal.
Definition: RCLCxPeerPos.cpp:72
ripple::Application::validators
virtual ValidatorList & validators()=0
ripple::KeyType::secp256k1
@ secp256k1
std::weak_ptr
STL class.
ripple::PeerImp::timer_
waitable_timer timer_
Definition: PeerImp.h:105
std::min
T min(T... args)
ripple::Serializer
Definition: Serializer.h:39
ripple::BuildInfo::getFullVersionString
std::string const & getFullVersionString()
Full server version string.
Definition: BuildInfo.cpp:74
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:268
ripple::Resource::Gossip::Item
Describes a single consumer.
Definition: Gossip.h:34
ripple::PeerImp::ShardInfo
Definition: PeerImp.h:75
ripple::PeerImp::getName
std::string getName() const
Definition: PeerImp.cpp:824
ripple::jtPACK
@ jtPACK
Definition: Job.h:41
ripple::PeerImp::gracefulClose_
bool gracefulClose_
Definition: PeerImp.h:186
beast::IP::AddressV4
boost::asio::ip::address_v4 AddressV4
Definition: IPAddressV4.h:34
ripple::PeerImp::latency_
boost::optional< std::chrono::milliseconds > latency_
Definition: PeerImp.h:140
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::ValidatorList::for_each_available
void for_each_available(std::function< void(std::string const &manifest, std::string const &blob, std::string const &signature, std::uint32_t version, PublicKey const &pubKey, std::size_t sequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
Definition: ValidatorList.cpp:774
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::jtVALIDATION_ut
@ jtVALIDATION_ut
Definition: Job.h:43
ripple::INVALID
@ INVALID
Definition: Transaction.h:45
ripple::OverlayImpl::remove
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
Definition: OverlayImpl.cpp:473
ripple::base_uint::zero
void zero()
Definition: base_uint.h:485
std::vector::begin
T begin(T... args)
ripple::PeerFinder::Manager::config
virtual Config config()=0
Returns the configuration for the manager.
std
STL namespace.
ripple::Resource::Consumer::disconnect
bool disconnect()
Returns true if the consumer should be disconnected.
Definition: Consumer.cpp:117
beast::severities::kWarning
@ kWarning
Definition: Journal.h:37
ripple::sha512Half
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:227
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:46
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:651
ripple::OverlayImpl::onPeerDeactivate
void onPeerDeactivate(Peer::id_t id)
Definition: OverlayImpl.cpp:675
ripple::PeerImp::hasShard
bool hasShard(std::uint32_t shardIndex) const override
Definition: PeerImp.cpp:464
ripple::Overlay::Setup::networkID
boost::optional< std::uint32_t > networkID
Definition: Overlay.h:78
ripple::Resource::Gossip::Item::address
beast::IP::Endpoint address
Definition: Gossip.h:39
ripple::invokeProtocolMessage
std::pair< std::size_t, boost::system::error_code > invokeProtocolMessage(Buffers const &buffers, Handler &handler)
Calls the handler for up to one protocol message in the passed buffers.
Definition: ProtocolMessage.h:263
ripple::snfWIRE
@ snfWIRE
Definition: SHAMapTreeNode.h:37
ripple::LedgerMaster::getCurrentLedgerIndex
LedgerIndex getCurrentLedgerIndex()
Definition: LedgerMaster.cpp:206
ripple::Resource::Consumer
An endpoint that consumes resources.
Definition: Consumer.h:33
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::OverlayImpl::lastLink
void lastLink(std::uint32_t id)
Called when the last link from a peer chain is received.
Definition: OverlayImpl.cpp:854
ripple::PeerImp::maxLedger_
LedgerIndex maxLedger_
Definition: PeerImp.h:133
ripple::PeerImp::run
void run()
Definition: PeerImp.cpp:122
ripple::Config::COMPRESSION
bool COMPRESSION
Definition: Config.h:174
ripple::LoadFeeTrack::setClusterFee
void setClusterFee(std::uint32_t fee)
Definition: LoadFeeTrack.h:111
ripple::PeerImp::large_sendq_
int large_sendq_
Definition: PeerImp.h:187
beast::severities::kDebug
@ kDebug
Definition: Journal.h:35
ripple::Tuning::readBufferBytes
@ readBufferBytes
Size of buffer used to read from the socket.
Definition: overlay/impl/Tuning.h:31
std::vector::empty
T empty(T... args)
ripple::Resource::feeLightPeer
const Charge feeLightPeer
ripple::jtPROPOSAL_ut
@ jtPROPOSAL_ut
Definition: Job.h:46
ripple::TokenType::NodePublic
@ NodePublic
ripple::PeerImp::last_status_
protocol::TMStatusChange last_status_
Definition: PeerImp.h:176
ripple::PeerImp::setPublisherListSequence
void setPublisherListSequence(PublicKey const &pubKey, std::size_t const seq) override
Definition: PeerImp.h:377
ripple::RCLCxPeerPos::suppressionID
uint256 const & suppressionID() const
Unique id used by hash router to suppress duplicates.
Definition: RCLCxPeerPos.h:88
ripple::PeerImp::supportsFeature
bool supportsFeature(ProtocolFeature f) const override
Definition: PeerImp.cpp:425
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:1231
std::stringstream::str
T str(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::PeerImp::makeResponse
http_response_type makeResponse(bool crawl, http_request_type const &req, beast::IP::Address remote_ip, uint256 const &sharedValue)
Definition: PeerImp.cpp:762
ripple::PeerImp::json
Json::Value json() override
Definition: PeerImp.cpp:309
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:197
ripple::ProtocolFeature::ValidatorListPropagation
@ ValidatorListPropagation
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
ripple::OverlayImpl::incPeerDisconnect
void incPeerDisconnect() override
Increment and retrieve counters for total peer disconnects, and disconnects we initiate for excessive...
Definition: OverlayImpl.h:328
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:67
std::vector::end
T end(T... args)
ripple::Job::getType
JobType getType() const
Definition: Job.cpp:52
ripple::PeerImp::makePrefix
static std::string makePrefix(id_t id)
Definition: PeerImp.cpp:624
ripple::PeerImp::usage_
Resource::Consumer usage_
Definition: PeerImp.h:177
ripple::RangeSet
boost::icl::interval_set< T, std::less, ClosedInterval< T > > RangeSet
A set of closed intervals over the domain T.
Definition: RangeSet.h:69
std::setw
T setw(T... args)
numeric
ripple::OverlayImpl
Definition: OverlayImpl.h:55
beast::IP::Endpoint::from_string_checked
static boost::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:35
std::max
T max(T... args)
beast::IP::Endpoint::at_port
Endpoint at_port(Port port) const
Returns a new Endpoint with a different port.
Definition: IPEndpoint.h:70
ripple::ValidatorList::trusted
bool trusted(PublicKey const &identity) const
Returns true if public key is trusted.
Definition: ValidatorList.cpp:561
ripple::PeerFinder::Endpoint::hops
int hops
Definition: PeerfinderManager.h:105
ripple::Serializer::getLength
int getLength() const
Definition: Serializer.h:197
ripple::OverlayImpl::reportTraffic
void reportTraffic(TrafficCount::category cat, bool isInbound, int bytes)
Definition: OverlayImpl.cpp:760
ripple::JobQueue::makeLoadEvent
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
Definition: JobQueue.cpp:181
ripple::PeerImp::getPeerShardInfo
boost::optional< hash_map< PublicKey, ShardInfo > > getPeerShardInfo() const
Return any known shard info from this peer and its sub peers.
Definition: PeerImp.cpp:567
ripple::PeerFinder::Endpoint
Describes a connectible peer address along with some metadata.
Definition: PeerfinderManager.h:99
ripple::PeerImp::shardInfoMutex_
std::mutex shardInfoMutex_
Definition: PeerImp.h:194
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:115
std::unique_ptr< stream_type >
ripple::PeerImp::cancelTimer
void cancelTimer()
Definition: PeerImp.cpp:615
ripple::PeerImp::fee_
Resource::Charge fee_
Definition: PeerImp.h:178
ripple::stringIsUint256Sized
static bool stringIsUint256Sized(std::string const &pBuffStr)
Definition: PeerImp.cpp:116
ripple::PeerFinder::Endpoint::address
beast::IP::Endpoint address
Definition: PeerfinderManager.h:106
ripple::PeerImp::stop
void stop() override
Definition: PeerImp.cpp:194
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::PeerImp::id_
const id_t id_
Definition: PeerImp.h:96
ripple::OverlayImpl::for_each
void for_each(UnaryFunc &&f) const
Definition: OverlayImpl.h:243
std::ref
T ref(T... args)
ripple::RCLCxPeerPos::checkSign
bool checkSign() const
Verify the signing hash of the proposal.
Definition: RCLCxPeerPos.cpp:55
std::exception::what
T what(T... args)
std::shared_lock
STL class.
ripple::PeerImp::fail
void fail(std::string const &reason)
Definition: PeerImp.cpp:524
ripple::PeerImp::cluster
bool cluster() const override
Returns true if this connection is a member of the cluster.
Definition: PeerImp.cpp:295
ripple::PeerImp::p_journal_
const beast::Journal p_journal_
Definition: PeerImp.h:100
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::Peer
Represents a peer connection in the overlay.
Definition: ripple/overlay/Peer.h:43
ripple::PeerImp::ShardInfo::shardIndexes
RangeSet< std::uint32_t > shardIndexes
Definition: PeerImp.h:78
ripple::jtLEDGER_REQ
@ jtLEDGER_REQ
Definition: Job.h:45
ripple::PeerImp::onReadMessage
void onReadMessage(error_code ec, std::size_t bytes_transferred)
Definition: PeerImp.cpp:888
ripple::ConsensusProposal< NodeID, uint256, uint256 >
std::chrono::steady_clock::now
T now(T... args)