rippled
Loading...
Searching...
No Matches
OverlayImpl.cpp
1#include <xrpld/app/misc/ValidatorList.h>
2#include <xrpld/app/misc/ValidatorSite.h>
3#include <xrpld/overlay/Cluster.h>
4#include <xrpld/overlay/detail/ConnectAttempt.h>
5#include <xrpld/overlay/detail/PeerImp.h>
6#include <xrpld/overlay/detail/TrafficCount.h>
7#include <xrpld/overlay/detail/Tuning.h>
8#include <xrpld/overlay/predicates.h>
9#include <xrpld/peerfinder/make_Manager.h>
10#include <xrpld/rpc/handlers/GetCounts.h>
11#include <xrpld/rpc/json_body.h>
12
13#include <xrpl/basics/base64.h>
14#include <xrpl/basics/make_SSLContext.h>
15#include <xrpl/basics/random.h>
16#include <xrpl/beast/core/LexicalCast.h>
17#include <xrpl/core/HashRouter.h>
18#include <xrpl/protocol/STTx.h>
19#include <xrpl/rdb/RelationalDatabase.h>
20#include <xrpl/server/NetworkOPs.h>
21#include <xrpl/server/SimpleWriter.h>
22#include <xrpl/server/Wallet.h>
23
24#include <boost/algorithm/string/predicate.hpp>
25#include <boost/asio/executor_work_guard.hpp>
26
27namespace xrpl {
28
29namespace CrawlOptions {
30enum {
32 Overlay = (1 << 0),
33 ServerInfo = (1 << 1),
34 ServerCounts = (1 << 2),
35 Unl = (1 << 3)
36};
37}
38
39//------------------------------------------------------------------------------
40
41OverlayImpl::Child::Child(OverlayImpl& overlay) : overlay_(overlay)
42{
43}
44
46{
47 overlay_.remove(*this);
48}
49
50//------------------------------------------------------------------------------
51
53{
54}
55
56void
58{
59 // This method is only ever called from the same strand that calls
60 // Timer::on_timer, ensuring they never execute concurrently.
61 stopping_ = true;
62 timer_.cancel();
63}
64
65void
67{
68 timer_.expires_after(std::chrono::seconds(1));
69 timer_.async_wait(
70 boost::asio::bind_executor(
71 overlay_.strand_,
72 std::bind(&Timer::on_timer, shared_from_this(), std::placeholders::_1)));
73}
74
75void
77{
78 if (ec || stopping_)
79 {
80 if (ec && ec != boost::asio::error::operation_aborted)
81 {
82 JLOG(overlay_.journal_.error()) << "on_timer: " << ec.message();
83 }
84 return;
85 }
86
87 overlay_.m_peerFinder->once_per_second();
88 overlay_.sendEndpoints();
89 overlay_.autoConnect();
90 if (overlay_.app_.config().TX_REDUCE_RELAY_ENABLE)
91 overlay_.sendTxQueue();
92
93 if ((++overlay_.timer_count_ % Tuning::checkIdlePeers) == 0)
94 overlay_.deleteIdlePeers();
95
96 async_wait();
97}
98
99//------------------------------------------------------------------------------
100
102 Application& app,
103 Setup const& setup,
104 ServerHandler& serverHandler,
106 Resolver& resolver,
107 boost::asio::io_context& io_context,
108 BasicConfig const& config,
109 beast::insight::Collector::ptr const& collector)
110 : app_(app)
111 , io_context_(io_context)
112 , work_(std::in_place, boost::asio::make_work_guard(io_context_))
113 , strand_(boost::asio::make_strand(io_context_))
114 , setup_(setup)
115 , journal_(app_.journal("Overlay"))
116 , serverHandler_(serverHandler)
118 , m_peerFinder(
119 PeerFinder::make_Manager(
120 io_context,
121 stopwatch(),
122 app_.journal("PeerFinder"),
123 config,
124 collector))
125 , m_resolver(resolver)
126 , next_id_(1)
127 , timer_count_(0)
128 , slots_(app.logs(), *this, app.config())
129 , m_stats(
130 std::bind(&OverlayImpl::collect_metrics, this),
131 collector,
132 [counts = m_traffic.getCounts(), collector]() {
134
135 for (auto const& pair : counts)
136 ret.emplace(pair.first, TrafficGauges(pair.second.name, collector));
137
138 return ret;
139 }())
140{
142}
143
144Handoff
146 std::unique_ptr<stream_type>&& stream_ptr,
147 http_request_type&& request,
148 endpoint_type remote_endpoint)
149{
150 auto const id = next_id_++;
151 beast::WrappedSink sink(app_.logs()["Peer"], makePrefix(id));
152 beast::Journal journal(sink);
153
154 Handoff handoff;
155 if (processRequest(request, handoff))
156 return handoff;
157 if (!isPeerUpgrade(request))
158 return handoff;
159
160 handoff.moved = true;
161
162 JLOG(journal.debug()) << "Peer connection upgrade from " << remote_endpoint;
163
164 error_code ec;
165 auto const local_endpoint(stream_ptr->next_layer().socket().local_endpoint(ec));
166 if (ec)
167 {
168 JLOG(journal.debug()) << remote_endpoint << " failed: " << ec.message();
169 return handoff;
170 }
171
174 if (consumer.disconnect(journal))
175 return handoff;
176
177 auto const [slot, result] = m_peerFinder->new_inbound_slot(
180
181 if (slot == nullptr)
182 {
183 // connection refused either IP limit exceeded or self-connect
184 handoff.moved = false;
185 JLOG(journal.debug()) << "Peer " << remote_endpoint << " refused, " << to_string(result);
186 return handoff;
187 }
188
189 // Validate HTTP request
190
191 {
192 auto const types = beast::rfc2616::split_commas(request["Connect-As"]);
193 if (std::find_if(types.begin(), types.end(), [](std::string const& s) {
194 return boost::iequals(s, "peer");
195 }) == types.end())
196 {
197 handoff.moved = false;
198 handoff.response = makeRedirectResponse(slot, request, remote_endpoint.address());
199 handoff.keep_alive = beast::rfc2616::is_keep_alive(request);
200 return handoff;
201 }
202 }
203
204 auto const negotiatedVersion = negotiateProtocolVersion(request["Upgrade"]);
205 if (!negotiatedVersion)
206 {
207 m_peerFinder->on_closed(slot);
208 handoff.moved = false;
209 handoff.response = makeErrorResponse(
210 slot, request, remote_endpoint.address(), "Unable to agree on a protocol version");
211 handoff.keep_alive = false;
212 return handoff;
213 }
214
215 auto const sharedValue = makeSharedValue(*stream_ptr, journal);
216 if (!sharedValue)
217 {
218 m_peerFinder->on_closed(slot);
219 handoff.moved = false;
220 handoff.response = makeErrorResponse(
221 slot, request, remote_endpoint.address(), "Incorrect security cookie");
222 handoff.keep_alive = false;
223 return handoff;
224 }
225
226 try
227 {
228 auto publicKey = verifyHandshake(
229 request,
230 *sharedValue,
233 remote_endpoint.address(),
234 app_);
235
236 consumer.setPublicKey(publicKey);
237
238 {
239 // The node gets a reserved slot if it is in our cluster
240 // or if it has a reservation.
241 bool const reserved = static_cast<bool>(app_.cluster().member(publicKey)) ||
242 app_.peerReservations().contains(publicKey);
243 auto const result = m_peerFinder->activate(slot, publicKey, reserved);
244 if (result != PeerFinder::Result::success)
245 {
246 m_peerFinder->on_closed(slot);
247 JLOG(journal.debug())
248 << "Peer " << remote_endpoint << " redirected, " << to_string(result);
249 handoff.moved = false;
250 handoff.response = makeRedirectResponse(slot, request, remote_endpoint.address());
251 handoff.keep_alive = false;
252 return handoff;
253 }
254 }
255
256 auto const peer = std::make_shared<PeerImp>(
257 app_,
258 id,
259 slot,
260 std::move(request),
261 publicKey,
262 *negotiatedVersion,
263 consumer,
264 std::move(stream_ptr),
265 *this);
266 {
267 // As we are not on the strand, run() must be called
268 // while holding the lock, otherwise new I/O can be
269 // queued after a call to stop().
270 std::lock_guard<decltype(mutex_)> lock(mutex_);
271 {
272 auto const result = m_peers.emplace(peer->slot(), peer);
273 XRPL_ASSERT(result.second, "xrpl::OverlayImpl::onHandoff : peer is inserted");
274 (void)result.second;
275 }
276 list_.emplace(peer.get(), peer);
277
278 peer->run();
279 }
280 handoff.moved = true;
281 return handoff;
282 }
283 catch (std::exception const& e)
284 {
285 JLOG(journal.debug()) << "Peer " << remote_endpoint << " fails handshake (" << e.what()
286 << ")";
287
288 m_peerFinder->on_closed(slot);
289 handoff.moved = false;
290 handoff.response = makeErrorResponse(slot, request, remote_endpoint.address(), e.what());
291 handoff.keep_alive = false;
292 return handoff;
293 }
294}
295
296//------------------------------------------------------------------------------
297
298bool
300{
301 if (!is_upgrade(request))
302 return false;
303 auto const versions = parseProtocolVersions(request["Upgrade"]);
304 return !versions.empty();
305}
306
309{
311 ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
312 return ss.str();
313}
314
318 http_request_type const& request,
319 address_type remote_address)
320{
321 boost::beast::http::response<json_body> msg;
322 msg.version(request.version());
323 msg.result(boost::beast::http::status::service_unavailable);
324 msg.insert("Server", BuildInfo::getFullVersionString());
325 {
327 ostr << remote_address;
328 msg.insert("Remote-Address", ostr.str());
329 }
330 msg.insert("Content-Type", "application/json");
331 msg.insert(boost::beast::http::field::connection, "close");
332 msg.body() = Json::objectValue;
333 {
334 Json::Value& ips = (msg.body()["peer-ips"] = Json::arrayValue);
335 for (auto const& _ : m_peerFinder->redirect(slot))
336 ips.append(_.address.to_string());
337 }
338 msg.prepare_payload();
340}
341
345 http_request_type const& request,
346 address_type remote_address,
347 std::string text)
348{
349 boost::beast::http::response<boost::beast::http::empty_body> msg;
350 msg.version(request.version());
351 msg.result(boost::beast::http::status::bad_request);
352 msg.reason("Bad Request (" + text + ")");
353 msg.insert("Server", BuildInfo::getFullVersionString());
354 msg.insert("Remote-Address", remote_address.to_string());
355 msg.insert(boost::beast::http::field::connection, "close");
356 msg.prepare_payload();
358}
359
360//------------------------------------------------------------------------------
361
362void
364{
365 XRPL_ASSERT(work_, "xrpl::OverlayImpl::connect : work is set");
366
367 auto usage = resourceManager().newOutboundEndpoint(remote_endpoint);
368 if (usage.disconnect(journal_))
369 {
370 JLOG(journal_.info()) << "Over resource limit: " << remote_endpoint;
371 return;
372 }
373
374 auto const [slot, result] = peerFinder().new_outbound_slot(remote_endpoint);
375 if (slot == nullptr)
376 {
377 JLOG(journal_.debug()) << "Connect: No slot for " << remote_endpoint << ": "
378 << to_string(result);
379 return;
380 }
381
383 app_,
386 usage,
388 next_id_++,
389 slot,
390 app_.journal("Peer"),
391 *this);
392
394 list_.emplace(p.get(), p);
395 p->run();
396}
397
398//------------------------------------------------------------------------------
399
400// Adds a peer that is already handshaked and active
401void
403{
404 beast::WrappedSink sink{journal_.sink(), peer->prefix()};
405 beast::Journal journal{sink};
406
408
409 {
410 auto const result = m_peers.emplace(peer->slot(), peer);
411 XRPL_ASSERT(result.second, "xrpl::OverlayImpl::add_active : peer is inserted");
412 (void)result.second;
413 }
414
415 {
416 auto const result = ids_.emplace(
418 XRPL_ASSERT(result.second, "xrpl::OverlayImpl::add_active : peer ID is inserted");
419 (void)result.second;
420 }
421
422 list_.emplace(peer.get(), peer);
423
424 JLOG(journal.debug()) << "activated";
425
426 // As we are not on the strand, run() must be called
427 // while holding the lock, otherwise new I/O can be
428 // queued after a call to stop().
429 peer->run();
430}
431
432void
434{
436 auto const iter = m_peers.find(slot);
437 XRPL_ASSERT(iter != m_peers.end(), "xrpl::OverlayImpl::remove : valid input");
438 m_peers.erase(iter);
439}
440
441void
443{
445 app_.config(),
446 serverHandler_.setup().overlay.port(),
447 app_.getValidationPublicKey().has_value(),
449
450 m_peerFinder->setConfig(config);
451 m_peerFinder->start();
452
453 // Populate our boot cache: if there are no entries in [ips] then we use
454 // the entries in [ips_fixed].
455 auto bootstrapIps = app_.config().IPS.empty() ? app_.config().IPS_FIXED : app_.config().IPS;
456
457 // If nothing is specified, default to several well-known high-capacity
458 // servers to serve as bootstrap:
459 if (bootstrapIps.empty())
460 {
461 // Pool of servers operated by Ripple Labs Inc. - https://ripple.com
462 bootstrapIps.push_back("r.ripple.com 51235");
463
464 // Pool of servers operated by ISRDC - https://isrdc.in
465 bootstrapIps.push_back("sahyadri.isrdc.in 51235");
466
467 // Pool of servers operated by @Xrpkuwait - https://xrpkuwait.com
468 bootstrapIps.push_back("hubs.xrpkuwait.com 51235");
469
470 // Pool of servers operated by XRPL Commons - https://xrpl-commons.org
471 bootstrapIps.push_back("hub.xrpl-commons.org 51235");
472 }
473
475 bootstrapIps,
476 [this](std::string const& name, std::vector<beast::IP::Endpoint> const& addresses) {
478 ips.reserve(addresses.size());
479 for (auto const& addr : addresses)
480 {
481 if (addr.port() == 0)
482 ips.push_back(to_string(addr.at_port(DEFAULT_PEER_PORT)));
483 else
484 ips.push_back(to_string(addr));
485 }
486
487 std::string const base("config: ");
488 if (!ips.empty())
489 m_peerFinder->addFallbackStrings(base + name, ips);
490 });
491
492 // Add the ips_fixed from the xrpld.cfg file
494 {
497 [this](std::string const& name, std::vector<beast::IP::Endpoint> const& addresses) {
499 ips.reserve(addresses.size());
500
501 for (auto& addr : addresses)
502 {
503 if (addr.port() == 0)
504 ips.emplace_back(addr.address(), DEFAULT_PEER_PORT);
505 else
506 ips.emplace_back(addr);
507 }
508
509 if (!ips.empty())
510 m_peerFinder->addFixedPeer(name, ips);
511 });
512 }
513 auto const timer = std::make_shared<Timer>(*this);
515 list_.emplace(timer.get(), timer);
516 timer_ = timer;
517 timer->async_wait();
518}
519
520void
522{
523 boost::asio::dispatch(strand_, std::bind(&OverlayImpl::stopChildren, this));
524 {
525 std::unique_lock<decltype(mutex_)> lock(mutex_);
526 cond_.wait(lock, [this] { return list_.empty(); });
527 }
528 m_peerFinder->stop();
529}
530
531//------------------------------------------------------------------------------
532//
533// PropertyStream
534//
535//------------------------------------------------------------------------------
536
537void
539{
540 beast::PropertyStream::Set set("traffic", stream);
541 auto const stats = m_traffic.getCounts();
542 for (auto const& pair : stats)
543 {
545 item["category"] = pair.second.name;
546 item["bytes_in"] = std::to_string(pair.second.bytesIn.load());
547 item["messages_in"] = std::to_string(pair.second.messagesIn.load());
548 item["bytes_out"] = std::to_string(pair.second.bytesOut.load());
549 item["messages_out"] = std::to_string(pair.second.messagesOut.load());
550 }
551}
552
553//------------------------------------------------------------------------------
559void
561{
562 beast::WrappedSink sink{journal_.sink(), peer->prefix()};
563 beast::Journal journal{sink};
564
565 // Now track this peer
566 {
568 auto const result(ids_.emplace(
570 XRPL_ASSERT(result.second, "xrpl::OverlayImpl::activate : peer ID is inserted");
571 (void)result.second;
572 }
573
574 JLOG(journal.debug()) << "activated";
575
576 // We just accepted this peer so we have non-zero active peers
577 XRPL_ASSERT(size(), "xrpl::OverlayImpl::activate : nonzero peers");
578}
579
580void
586
587void
590 std::shared_ptr<PeerImp> const& from)
591{
592 auto const n = m->list_size();
593 auto const& journal = from->pJournal();
594
595 protocol::TMManifests relay;
596
597 for (std::size_t i = 0; i < n; ++i)
598 {
599 auto& s = m->list().Get(i).stobject();
600
601 if (auto mo = deserializeManifest(s))
602 {
603 auto const serialized = mo->serialized;
604
605 auto const result = app_.validatorManifests().applyManifest(std::move(*mo));
606
607 if (result == ManifestDisposition::accepted)
608 {
609 relay.add_list()->set_stobject(s);
610
611 // N.B.: this is important; the applyManifest call above moves
612 // the loaded Manifest out of the optional so we need to
613 // reload it here.
614 mo = deserializeManifest(serialized);
615 XRPL_ASSERT(
616 mo,
617 "xrpl::OverlayImpl::onManifests : manifest "
618 "deserialization succeeded");
619
620 app_.getOPs().pubManifest(*mo);
621
622 if (app_.validators().listed(mo->masterKey))
623 {
624 auto db = app_.getWalletDB().checkoutDb();
625 addValidatorManifest(*db, serialized);
626 }
627 }
628 }
629 else
630 {
631 JLOG(journal.debug()) << "Malformed manifest #" << i + 1 << ": " << strHex(s);
632 continue;
633 }
634 }
635
636 if (!relay.list().empty())
637 for_each([m2 = std::make_shared<Message>(relay, protocol::mtMANIFESTS)](
638 std::shared_ptr<PeerImp>&& p) { p->send(m2); });
639}
640
641void
646
647void
658{
660 return ids_.size();
661}
662
663int
665{
666 return m_peerFinder->config().maxPeers;
667}
668
671{
672 using namespace std::chrono;
673 Json::Value jv;
674 auto& av = jv["active"] = Json::Value(Json::arrayValue);
675
677 auto& pv = av.append(Json::Value(Json::objectValue));
678 pv[jss::public_key] = base64_encode(sp->getNodePublic().data(), sp->getNodePublic().size());
679 pv[jss::type] = sp->slot()->inbound() ? "in" : "out";
680 pv[jss::uptime] = static_cast<std::uint32_t>(duration_cast<seconds>(sp->uptime()).count());
681 if (sp->crawl())
682 {
683 pv[jss::ip] = sp->getRemoteAddress().address().to_string();
684 if (sp->slot()->inbound())
685 {
686 if (auto port = sp->slot()->listening_port())
687 pv[jss::port] = *port;
688 }
689 else
690 {
691 pv[jss::port] = std::to_string(sp->getRemoteAddress().port());
692 }
693 }
694
695 {
696 auto version{sp->getVersion()};
697 if (!version.empty())
698 // Could move here if Json::value supported moving from strings
699 pv[jss::version] = std::string{version};
700 }
701
702 std::uint32_t minSeq, maxSeq;
703 sp->ledgerRange(minSeq, maxSeq);
704 if (minSeq != 0 || maxSeq != 0)
705 pv[jss::complete_ledgers] = std::to_string(minSeq) + "-" + std::to_string(maxSeq);
706 });
707
708 return jv;
709}
710
713{
714 bool const humanReadable = false;
715 bool const admin = false;
716 bool const counters = false;
717
718 Json::Value server_info = app_.getOPs().getServerInfo(humanReadable, admin, counters);
719
720 // Filter out some information
721 server_info.removeMember(jss::hostid);
722 server_info.removeMember(jss::load_factor_fee_escalation);
723 server_info.removeMember(jss::load_factor_fee_queue);
724 server_info.removeMember(jss::validation_quorum);
725
726 if (server_info.isMember(jss::validated_ledger))
727 {
728 Json::Value& validated_ledger = server_info[jss::validated_ledger];
729
730 validated_ledger.removeMember(jss::base_fee);
731 validated_ledger.removeMember(jss::reserve_base_xrp);
732 validated_ledger.removeMember(jss::reserve_inc_xrp);
733 }
734
735 return server_info;
736}
737
743
746{
747 Json::Value validators = app_.validators().getJson();
748
749 if (validators.isMember(jss::publisher_lists))
750 {
751 Json::Value& publisher_lists = validators[jss::publisher_lists];
752
753 for (auto& publisher : publisher_lists)
754 {
755 publisher.removeMember(jss::list);
756 }
757 }
758
759 validators.removeMember(jss::signing_keys);
760 validators.removeMember(jss::trusted_validator_keys);
761 validators.removeMember(jss::validation_quorum);
762
763 Json::Value validatorSites = app_.validatorSites().getJson();
764
765 if (validatorSites.isMember(jss::validator_sites))
766 {
767 validators[jss::validator_sites] = std::move(validatorSites[jss::validator_sites]);
768 }
769
770 return validators;
771}
772
773// Returns information on verified peers.
776{
778 for (auto const& peer : getActivePeers())
779 {
780 json.append(peer->json());
781 }
782 return json;
783}
784
785bool
787{
788 if (req.target() != "/crawl" || setup_.crawlOptions == CrawlOptions::Disabled)
789 return false;
790
791 boost::beast::http::response<json_body> msg;
792 msg.version(req.version());
793 msg.result(boost::beast::http::status::ok);
794 msg.insert("Server", BuildInfo::getFullVersionString());
795 msg.insert("Content-Type", "application/json");
796 msg.insert("Connection", "close");
797 msg.body()["version"] = Json::Value(2u);
798
800 {
801 msg.body()["overlay"] = getOverlayInfo();
802 }
804 {
805 msg.body()["server"] = getServerInfo();
806 }
808 {
809 msg.body()["counts"] = getServerCounts();
810 }
812 {
813 msg.body()["unl"] = getUnlInfo();
814 }
815
816 msg.prepare_payload();
818 return true;
819}
820
821bool
823{
824 // If the target is in the form "/vl/<validator_list_public_key>",
825 // return the most recent validator list for that key.
826 constexpr std::string_view prefix("/vl/");
827
828 if (!req.target().starts_with(prefix.data()) || !setup_.vlEnabled)
829 return false;
830
831 std::uint32_t version = 1;
832
833 boost::beast::http::response<json_body> msg;
834 msg.version(req.version());
835 msg.insert("Server", BuildInfo::getFullVersionString());
836 msg.insert("Content-Type", "application/json");
837 msg.insert("Connection", "close");
838
839 auto fail = [&msg, &handoff](auto status) {
840 msg.result(status);
841 msg.insert("Content-Length", "0");
842
843 msg.body() = Json::nullValue;
844
845 msg.prepare_payload();
847 return true;
848 };
849
850 std::string_view key = req.target().substr(prefix.size());
851
852 if (auto slash = key.find('/'); slash != std::string_view::npos)
853 {
854 auto verString = key.substr(0, slash);
855 if (!boost::conversion::try_lexical_convert(verString, version))
856 return fail(boost::beast::http::status::bad_request);
857 key = key.substr(slash + 1);
858 }
859
860 if (key.empty())
861 return fail(boost::beast::http::status::bad_request);
862
863 // find the list
864 auto vl = app_.validators().getAvailable(key, version);
865
866 if (!vl)
867 {
868 // 404 not found
869 return fail(boost::beast::http::status::not_found);
870 }
871 else if (!*vl)
872 {
873 return fail(boost::beast::http::status::bad_request);
874 }
875 else
876 {
877 msg.result(boost::beast::http::status::ok);
878
879 msg.body() = *vl;
880
881 msg.prepare_payload();
883 return true;
884 }
885}
886
887bool
889{
890 if (req.target() != "/health")
891 return false;
892 boost::beast::http::response<json_body> msg;
893 msg.version(req.version());
894 msg.insert("Server", BuildInfo::getFullVersionString());
895 msg.insert("Content-Type", "application/json");
896 msg.insert("Connection", "close");
897
898 auto info = getServerInfo();
899
900 int last_validated_ledger_age = -1;
901 if (info.isMember(jss::validated_ledger))
902 last_validated_ledger_age = info[jss::validated_ledger][jss::age].asInt();
903 bool amendment_blocked = false;
904 if (info.isMember(jss::amendment_blocked))
905 amendment_blocked = true;
906 int number_peers = info[jss::peers].asInt();
907 std::string server_state = info[jss::server_state].asString();
908 auto load_factor = info[jss::load_factor_server].asDouble() / info[jss::load_base].asDouble();
909
910 enum { healthy, warning, critical };
911 int health = healthy;
912 auto set_health = [&health](int state) {
913 if (health < state)
914 health = state;
915 };
916
917 msg.body()[jss::info] = Json::objectValue;
918 if (last_validated_ledger_age >= 7 || last_validated_ledger_age < 0)
919 {
920 msg.body()[jss::info][jss::validated_ledger] = last_validated_ledger_age;
921 if (last_validated_ledger_age < 20)
922 set_health(warning);
923 else
924 set_health(critical);
925 }
926
927 if (amendment_blocked)
928 {
929 msg.body()[jss::info][jss::amendment_blocked] = true;
930 set_health(critical);
931 }
932
933 if (number_peers <= 7)
934 {
935 msg.body()[jss::info][jss::peers] = number_peers;
936 if (number_peers != 0)
937 set_health(warning);
938 else
939 set_health(critical);
940 }
941
942 if (!(server_state == "full" || server_state == "validating" || server_state == "proposing"))
943 {
944 msg.body()[jss::info][jss::server_state] = server_state;
945 if (server_state == "syncing" || server_state == "tracking" || server_state == "connected")
946 {
947 set_health(warning);
948 }
949 else
950 set_health(critical);
951 }
952
953 if (load_factor > 100)
954 {
955 msg.body()[jss::info][jss::load_factor] = load_factor;
956 if (load_factor < 1000)
957 set_health(warning);
958 else
959 set_health(critical);
960 }
961
962 switch (health)
963 {
964 case healthy:
965 msg.result(boost::beast::http::status::ok);
966 break;
967 case warning:
968 msg.result(boost::beast::http::status::service_unavailable);
969 break;
970 case critical:
971 msg.result(boost::beast::http::status::internal_server_error);
972 break;
973 }
974
975 msg.prepare_payload();
977 return true;
978}
979
980bool
982{
983 // Take advantage of || short-circuiting
984 return processCrawl(req, handoff) || processValidatorList(req, handoff) ||
985 processHealth(req, handoff);
986}
987
990{
992 ret.reserve(size());
993
994 for_each([&ret](std::shared_ptr<PeerImp>&& sp) { ret.emplace_back(std::move(sp)); });
995
996 return ret;
997}
998
1001 std::set<Peer::id_t> const& toSkip,
1002 std::size_t& active,
1003 std::size_t& disabled,
1004 std::size_t& enabledInSkip) const
1005{
1007 std::lock_guard lock(mutex_);
1008
1009 active = ids_.size();
1010 disabled = enabledInSkip = 0;
1011 ret.reserve(ids_.size());
1012
1013 // NOTE The purpose of p is to delay the destruction of PeerImp
1015 for (auto& [id, w] : ids_)
1016 {
1017 if (p = w.lock(); p != nullptr)
1018 {
1019 bool const reduceRelayEnabled = p->txReduceRelayEnabled();
1020 // tx reduced relay feature disabled
1021 if (!reduceRelayEnabled)
1022 ++disabled;
1023
1024 if (toSkip.count(id) == 0)
1025 ret.emplace_back(std::move(p));
1026 else if (reduceRelayEnabled)
1027 ++enabledInSkip;
1028 }
1029 }
1030
1031 return ret;
1032}
1033
1034void
1036{
1037 for_each([index](std::shared_ptr<PeerImp>&& sp) { sp->checkTracking(index); });
1038}
1039
1042{
1043 std::lock_guard lock(mutex_);
1044 auto const iter = ids_.find(id);
1045 if (iter != ids_.end())
1046 return iter->second.lock();
1047 return {};
1048}
1049
1050// A public key hash map was not used due to the peer connect/disconnect
1051// update overhead outweighing the performance of a small set linear search.
1054{
1055 std::lock_guard lock(mutex_);
1056 // NOTE The purpose of peer is to delay the destruction of PeerImp
1058 for (auto const& e : ids_)
1059 {
1060 if (peer = e.second.lock(); peer != nullptr)
1061 {
1062 if (peer->getNodePublic() == pubKey)
1063 return peer;
1064 }
1065 }
1066 return {};
1067}
1068
1069void
1070OverlayImpl::broadcast(protocol::TMProposeSet& m)
1071{
1072 auto const sm = std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER);
1073 for_each([&](std::shared_ptr<PeerImp>&& p) { p->send(sm); });
1074}
1075
1077OverlayImpl::relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey const& validator)
1078{
1079 if (auto const toSkip = app_.getHashRouter().shouldRelay(uid))
1080 {
1081 auto const sm = std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER, validator);
1083 if (toSkip->find(p->id()) == toSkip->end())
1084 p->send(sm);
1085 });
1086 return *toSkip;
1087 }
1088 return {};
1089}
1090
1091void
1092OverlayImpl::broadcast(protocol::TMValidation& m)
1093{
1094 auto const sm = std::make_shared<Message>(m, protocol::mtVALIDATION);
1095 for_each([sm](std::shared_ptr<PeerImp>&& p) { p->send(sm); });
1096}
1097
1099OverlayImpl::relay(protocol::TMValidation& m, uint256 const& uid, PublicKey const& validator)
1100{
1101 if (auto const toSkip = app_.getHashRouter().shouldRelay(uid))
1102 {
1103 auto const sm = std::make_shared<Message>(m, protocol::mtVALIDATION, validator);
1105 if (toSkip->find(p->id()) == toSkip->end())
1106 p->send(sm);
1107 });
1108 return *toSkip;
1109 }
1110 return {};
1111}
1112
1115{
1117
1118 if (auto seq = app_.validatorManifests().sequence(); seq != manifestListSeq_)
1119 {
1120 protocol::TMManifests tm;
1121
1123 [&tm](std::size_t s) { tm.mutable_list()->Reserve(s); },
1124 [&tm, &hr = app_.getHashRouter()](Manifest const& manifest) {
1125 tm.add_list()->set_stobject(manifest.serialized.data(), manifest.serialized.size());
1126 hr.addSuppression(manifest.hash());
1127 });
1128
1130
1131 if (tm.list_size() != 0)
1132 manifestMessage_ = std::make_shared<Message>(tm, protocol::mtMANIFESTS);
1133
1134 manifestListSeq_ = seq;
1135 }
1136
1137 return manifestMessage_;
1138}
1139
1140void
1142 uint256 const& hash,
1144 std::set<Peer::id_t> const& toSkip)
1145{
1146 bool relay = tx.has_value();
1147 if (relay)
1148 {
1149 auto& txn = tx->get();
1150 SerialIter sit(makeSlice(txn.rawtransaction()));
1151 try
1152 {
1153 relay = !isPseudoTx(STTx{sit});
1154 }
1155 catch (std::exception const&)
1156 {
1157 // Could not construct STTx, not relaying
1158 JLOG(journal_.debug()) << "Could not construct STTx: " << hash;
1159 return;
1160 }
1161 }
1162
1163 Overlay::PeerSequence peers = {};
1164 std::size_t total = 0;
1165 std::size_t disabled = 0;
1166 std::size_t enabledInSkip = 0;
1167
1168 if (!relay)
1169 {
1171 return;
1172
1173 peers = getActivePeers(toSkip, total, disabled, enabledInSkip);
1174 JLOG(journal_.trace()) << "not relaying tx, total peers " << peers.size();
1175 for (auto const& p : peers)
1176 p->addTxQueue(hash);
1177 return;
1178 }
1179
1180 auto& txn = tx->get();
1181 auto const sm = std::make_shared<Message>(txn, protocol::mtTRANSACTION);
1182 peers = getActivePeers(toSkip, total, disabled, enabledInSkip);
1183 auto const minRelay = app_.config().TX_REDUCE_RELAY_MIN_PEERS + disabled;
1184
1185 if (!app_.config().TX_REDUCE_RELAY_ENABLE || total <= minRelay)
1186 {
1187 for (auto const& p : peers)
1188 p->send(sm);
1190 txMetrics_.addMetrics(total, toSkip.size(), 0);
1191 return;
1192 }
1193
1194 // We have more peers than the minimum (disabled + minimum enabled),
1195 // relay to all disabled and some randomly selected enabled that
1196 // do not have the transaction.
1197 auto const enabledTarget = app_.config().TX_REDUCE_RELAY_MIN_PEERS +
1198 (total - minRelay) * app_.config().TX_RELAY_PERCENTAGE / 100;
1199
1200 txMetrics_.addMetrics(enabledTarget, toSkip.size(), disabled);
1201
1202 if (enabledTarget > enabledInSkip)
1203 std::shuffle(peers.begin(), peers.end(), default_prng());
1204
1205 JLOG(journal_.trace()) << "relaying tx, total peers " << peers.size() << " selected "
1206 << enabledTarget << " skip " << toSkip.size() << " disabled "
1207 << disabled;
1208
1209 // count skipped peers with the enabled feature towards the quota
1210 std::uint16_t enabledAndRelayed = enabledInSkip;
1211 for (auto const& p : peers)
1212 {
1213 // always relay to a peer with the disabled feature
1214 if (!p->txReduceRelayEnabled())
1215 {
1216 p->send(sm);
1217 }
1218 else if (enabledAndRelayed < enabledTarget)
1219 {
1220 enabledAndRelayed++;
1221 p->send(sm);
1222 }
1223 else
1224 {
1225 p->addTxQueue(hash);
1226 }
1227 }
1228}
1229
1230//------------------------------------------------------------------------------
1231
1232void
1234{
1235 std::lock_guard lock(mutex_);
1236 list_.erase(&child);
1237 if (list_.empty())
1238 cond_.notify_all();
1239}
1240
1241void
1243{
1244 // Calling list_[].second->stop() may cause list_ to be modified
1245 // (OverlayImpl::remove() may be called on this same thread). So
1246 // iterating directly over list_ to call child->stop() could lead to
1247 // undefined behavior.
1248 //
1249 // Therefore we copy all of the weak/shared ptrs out of list_ before we
1250 // start calling stop() on them. That guarantees OverlayImpl::remove()
1251 // won't be called until vector<> children leaves scope.
1253 {
1254 std::lock_guard lock(mutex_);
1255 if (!work_)
1256 return;
1258
1259 children.reserve(list_.size());
1260 for (auto const& element : list_)
1261 {
1262 children.emplace_back(element.second.lock());
1263 }
1264 } // lock released
1265
1266 for (auto const& child : children)
1267 {
1268 if (child != nullptr)
1269 child->stop();
1270 }
1271}
1272
1273void
1275{
1276 auto const result = m_peerFinder->autoconnect();
1277 for (auto addr : result)
1278 connect(addr);
1279}
1280
1281void
1283{
1284 auto const result = m_peerFinder->buildEndpointsForPeers();
1285 for (auto const& e : result)
1286 {
1288 {
1289 std::lock_guard lock(mutex_);
1290 auto const iter = m_peers.find(e.first);
1291 if (iter != m_peers.end())
1292 peer = iter->second.lock();
1293 }
1294 if (peer)
1295 peer->sendEndpoints(e.second.begin(), e.second.end());
1296 }
1297}
1298
1299void
1301{
1302 for_each([](auto const& p) {
1303 if (p->txReduceRelayEnabled())
1304 p->sendTxQueue();
1305 });
1306}
1307
1309makeSquelchMessage(PublicKey const& validator, bool squelch, uint32_t squelchDuration)
1310{
1311 protocol::TMSquelch m;
1312 m.set_squelch(squelch);
1313 m.set_validatorpubkey(validator.data(), validator.size());
1314 if (squelch)
1315 m.set_squelchduration(squelchDuration);
1316 return std::make_shared<Message>(m, protocol::mtSQUELCH);
1317}
1318
1319void
1321{
1322 if (auto peer = findPeerByShortID(id); peer)
1323 {
1324 // optimize - multiple message with different
1325 // validator might be sent to the same peer
1326 peer->send(makeSquelchMessage(validator, false, 0));
1327 }
1328}
1329
1330void
1331OverlayImpl::squelch(PublicKey const& validator, Peer::id_t id, uint32_t squelchDuration) const
1332{
1333 if (auto peer = findPeerByShortID(id); peer)
1334 {
1335 peer->send(makeSquelchMessage(validator, true, squelchDuration));
1336 }
1337}
1338
1339void
1341 uint256 const& key,
1342 PublicKey const& validator,
1343 std::set<Peer::id_t>&& peers,
1344 protocol::MessageType type)
1345{
1346 if (!slots_.baseSquelchReady())
1347 return;
1348
1349 if (!strand_.running_in_this_thread())
1350 return post(
1351 strand_,
1352 // Must capture copies of reference parameters (i.e. key, validator)
1353 [this, key = key, validator = validator, peers = std::move(peers), type]() mutable {
1354 updateSlotAndSquelch(key, validator, std::move(peers), type);
1355 });
1356
1357 for (auto id : peers)
1358 slots_.updateSlotAndSquelch(key, validator, id, type, [&]() {
1360 });
1361}
1362
1363void
1365 uint256 const& key,
1366 PublicKey const& validator,
1367 Peer::id_t peer,
1368 protocol::MessageType type)
1369{
1370 if (!slots_.baseSquelchReady())
1371 return;
1372
1373 if (!strand_.running_in_this_thread())
1374 return post(
1375 strand_,
1376 // Must capture copies of reference parameters (i.e. key, validator)
1377 [this, key = key, validator = validator, peer, type]() {
1378 updateSlotAndSquelch(key, validator, peer, type);
1379 });
1380
1381 slots_.updateSlotAndSquelch(key, validator, peer, type, [&]() {
1383 });
1384}
1385
1386void
1388{
1389 if (!strand_.running_in_this_thread())
1390 return post(strand_, std::bind(&OverlayImpl::deletePeer, this, id));
1391
1392 slots_.deletePeer(id, true);
1393}
1394
1395void
1397{
1398 if (!strand_.running_in_this_thread())
1399 return post(strand_, std::bind(&OverlayImpl::deleteIdlePeers, this));
1400
1401 slots_.deleteIdlePeers();
1402}
1403
1404//------------------------------------------------------------------------------
1405
1408{
1409 Overlay::Setup setup;
1410
1411 {
1412 auto const& section = config.section("overlay");
1413 setup.context = make_SSLContext("");
1414
1415 set(setup.ipLimit, "ip_limit", section);
1416 if (setup.ipLimit < 0)
1417 Throw<std::runtime_error>("Configured IP limit is invalid");
1418
1419 std::string ip;
1420 set(ip, "public_ip", section);
1421 if (!ip.empty())
1422 {
1423 boost::system::error_code ec;
1424 setup.public_ip = boost::asio::ip::make_address(ip, ec);
1425 if (ec || beast::IP::is_private(setup.public_ip))
1426 Throw<std::runtime_error>("Configured public IP is invalid");
1427 }
1428 }
1429
1430 {
1431 auto const& section = config.section("crawl");
1432 auto const& values = section.values();
1433
1434 if (values.size() > 1)
1435 {
1436 Throw<std::runtime_error>("Configured [crawl] section is invalid, too many values");
1437 }
1438
1439 bool crawlEnabled = true;
1440
1441 // Only allow "0|1" as a value
1442 if (values.size() == 1)
1443 {
1444 try
1445 {
1446 crawlEnabled = boost::lexical_cast<bool>(values.front());
1447 }
1448 catch (boost::bad_lexical_cast const&)
1449 {
1450 Throw<std::runtime_error>(
1451 "Configured [crawl] section has invalid value: " + values.front());
1452 }
1453 }
1454
1455 if (crawlEnabled)
1456 {
1457 if (get<bool>(section, "overlay", true))
1458 {
1460 }
1461 if (get<bool>(section, "server", true))
1462 {
1464 }
1465 if (get<bool>(section, "counts", false))
1466 {
1468 }
1469 if (get<bool>(section, "unl", true))
1470 {
1472 }
1473 }
1474 }
1475 {
1476 auto const& section = config.section("vl");
1477
1478 set(setup.vlEnabled, "enabled", section);
1479 }
1480
1481 try
1482 {
1483 auto id = config.legacy("network_id");
1484
1485 if (!id.empty())
1486 {
1487 if (id == "main")
1488 id = "0";
1489
1490 if (id == "testnet")
1491 id = "1";
1492
1493 if (id == "devnet")
1494 id = "2";
1495
1496 setup.networkID = beast::lexicalCastThrow<std::uint32_t>(id);
1497 }
1498 }
1499 catch (...)
1500 {
1501 Throw<std::runtime_error>(
1502 "Configured [network_id] section is invalid: must be a number "
1503 "or one of the strings 'main', 'testnet' or 'devnet'.");
1504 }
1505
1506 return setup;
1507}
1508
1511 Application& app,
1512 Overlay::Setup const& setup,
1513 ServerHandler& serverHandler,
1514 Resource::Manager& resourceManager,
1515 Resolver& resolver,
1516 boost::asio::io_context& io_context,
1517 BasicConfig const& config,
1518 beast::insight::Collector::ptr const& collector)
1519{
1521 app, setup, serverHandler, resourceManager, resolver, io_context, config, collector);
1522}
1523
1524} // namespace xrpl
T begin(T... args)
T bind(T... args)
Represents a JSON value.
Definition json_value.h:130
Value & append(Value const &value)
Append value to array at the end.
Value removeMember(char const *key)
Remove and return the named member.
bool isMember(char const *key) const
Return true if the object has a member named key.
A version-independent IP address and port combination.
Definition IPEndpoint.h:18
A generic endpoint for log messages.
Definition Journal.h:40
Stream debug() const
Definition Journal.h:301
Sink & sink() const
Returns the Sink associated with this Journal.
Definition Journal.h:270
Stream info() const
Definition Journal.h:307
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
std::string const & name() const
Returns the name of this source.
void add(Source &source)
Add a child source.
Wraps a Journal::Sink to prefix its output with a string.
Definition WrappedSink.h:14
virtual Config & config()=0
virtual std::optional< PublicKey const > getValidationPublicKey() const =0
Holds unparsed configuration information.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
Section & section(std::string const &name)
Returns the section with the given name.
std::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
Definition Cluster.cpp:19
bool TX_REDUCE_RELAY_ENABLE
Definition Config.h:239
std::vector< std::string > IPS
Definition Config.h:124
bool standalone() const
Definition Config.h:312
std::size_t TX_RELAY_PERCENTAGE
Definition Config.h:252
bool TX_REDUCE_RELAY_METRICS
Definition Config.h:246
std::vector< std::string > IPS_FIXED
Definition Config.h:127
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition Config.h:249
LockedSociSession checkoutDb()
std::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
virtual void pubManifest(Manifest const &)=0
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition Manifest.h:402
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition Manifest.cpp:351
std::uint32_t sequence() const
A monotonically increasing number used to detect new manifests.
Definition Manifest.h:255
virtual Json::Value getServerInfo(bool human, bool admin, bool counters)=0
Child(OverlayImpl &overlay)
void deletePeer(Peer::id_t id)
Called when the peer is deleted.
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
std::weak_ptr< Timer > timer_
Definition OverlayImpl.h:89
boost::asio::io_context & io_context_
Definition OverlayImpl.h:84
bool processRequest(http_request_type const &req, Handoff &handoff)
Handles non-peer protocol requests.
OverlayImpl(Application &app, Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_context &io_context, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
boost::asio::ip::address address_type
Definition OverlayImpl.h:62
static bool isPeerUpgrade(http_request_type const &request)
Resource::Manager & m_resourceManager
Definition OverlayImpl.h:94
boost::system::error_code error_code
Definition OverlayImpl.h:64
bool processCrawl(http_request_type const &req, Handoff &handoff)
Handles crawl requests.
bool processHealth(http_request_type const &req, Handoff &handoff)
Handles health requests.
Json::Value getServerCounts()
Returns information about the local server's performance counters.
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...
Handoff onHandoff(std::unique_ptr< stream_type > &&bundle, http_request_type &&request, endpoint_type remote_endpoint) override
Conditionally accept an incoming HTTP request.
std::optional< boost::asio::executor_work_guard< boost::asio::io_context::executor_type > > work_
Definition OverlayImpl.h:85
void reportOutboundTraffic(TrafficCount::category cat, int bytes)
void for_each(UnaryFunc &&f) const
void stop() override
void connect(beast::IP::Endpoint const &remote_endpoint) override
Establish a peer connection to the specified endpoint.
std::size_t size() const override
The number of active peers on the network Active peers are only those peers that have completed the h...
ServerHandler & serverHandler_
Definition OverlayImpl.h:93
void onManifests(std::shared_ptr< protocol::TMManifests > const &m, std::shared_ptr< PeerImp > const &from)
void broadcast(protocol::TMProposeSet &m) override
Broadcast a proposal.
std::shared_ptr< Writer > makeErrorResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address, std::string msg)
reduce_relay::Slots< UptimeClock > slots_
hash_map< Peer::id_t, std::weak_ptr< PeerImp > > ids_
Definition OverlayImpl.h:98
void deleteIdlePeers()
Check if peers stopped relaying messages and if slots stopped receiving messages from the validator.
TrafficCount m_traffic
Definition OverlayImpl.h:96
void squelch(PublicKey const &validator, Peer::id_t const id, std::uint32_t squelchDuration) const override
Squelch handler.
void sendTxQueue()
Send once a second transactions' hashes aggregated by peers.
std::shared_ptr< Message > manifestMessage_
std::unique_ptr< PeerFinder::Manager > m_peerFinder
Definition OverlayImpl.h:95
std::optional< std::uint32_t > manifestListSeq_
void onWrite(beast::PropertyStream::Map &stream) override
Subclass override.
void add_active(std::shared_ptr< PeerImp > const &peer)
PeerFinder::Manager & peerFinder()
Application & app_
Definition OverlayImpl.h:83
std::recursive_mutex mutex_
Definition OverlayImpl.h:87
Resource::Manager & resourceManager()
beast::Journal const journal_
Definition OverlayImpl.h:92
boost::asio::ip::tcp::endpoint endpoint_type
Definition OverlayImpl.h:63
void onPeerDeactivate(Peer::id_t id)
std::mutex manifestLock_
boost::asio::strand< boost::asio::io_context::executor_type > strand_
Definition OverlayImpl.h:86
Json::Value json() override
Return diagnostics on the status of all peers.
static std::string makePrefix(std::uint32_t id)
Setup const & setup() const
std::set< Peer::id_t > relay(protocol::TMProposeSet &m, uint256 const &uid, PublicKey const &validator) override
Relay a proposal.
static bool is_upgrade(boost::beast::http::header< true, Fields > const &req)
metrics::TxMetrics txMetrics_
boost::container::flat_map< Child *, std::weak_ptr< Child > > list_
Definition OverlayImpl.h:90
int limit() override
Returns the maximum number of peers we are configured to allow.
std::condition_variable_any cond_
Definition OverlayImpl.h:88
hash_map< std::shared_ptr< PeerFinder::Slot >, std::weak_ptr< PeerImp > > m_peers
Definition OverlayImpl.h:97
std::shared_ptr< Message > getManifestsMessage()
Json::Value getUnlInfo()
Returns information about the local server's UNL.
std::shared_ptr< Peer > findPeerByPublicKey(PublicKey const &pubKey) override
Returns the peer with the matching public key, or null.
std::shared_ptr< Writer > makeRedirectResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address)
std::atomic< Peer::id_t > next_id_
void reportInboundTraffic(TrafficCount::category cat, int bytes)
bool processValidatorList(http_request_type const &req, Handoff &handoff)
Handles validator list requests.
void checkTracking(std::uint32_t) override
Calls the checkTracking function on each peer.
Resolver & m_resolver
Definition OverlayImpl.h:99
Json::Value getServerInfo()
Returns information about the local server.
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, std::set< Peer::id_t > &&peers, protocol::MessageType type)
Updates message count for validator/peer.
std::shared_ptr< Peer > findPeerByShortID(Peer::id_t const &id) const override
Returns the peer with the matching short id, or null.
void start() override
PeerSequence getActivePeers() const override
Returns a sequence representing the current list of peers.
Json::Value getOverlayInfo()
Returns information about peers on the overlay network.
void unsquelch(PublicKey const &validator, Peer::id_t id) const override
Unsquelch handler.
Manages the set of connected peers.
Definition Overlay.h:29
virtual std::pair< std::shared_ptr< Slot >, Result > new_outbound_slot(beast::IP::Endpoint const &remote_endpoint)=0
Create a new outbound slot with the specified remote endpoint.
bool contains(PublicKey const &nodeId)
A public key.
Definition PublicKey.h:42
void resolve(std::vector< std::string > const &names, Handler handler)
resolve all hostnames on the list
Definition Resolver.h:36
Tracks load and resource consumption.
virtual Consumer newOutboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by outbound IP address and port.
virtual Consumer newInboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by inbound IP address or the forwarded IP if proxied.
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition BasicConfig.h:58
void setup(Setup const &setup, beast::Journal journal)
virtual Logs & logs()=0
virtual ValidatorList & validators()=0
virtual NetworkOPs & getOPs()=0
virtual PeerReservationTable & peerReservations()=0
virtual Cluster & cluster()=0
virtual HashRouter & getHashRouter()=0
virtual DatabaseCon & getWalletDB()=0
Retrieve the "wallet database".
virtual ValidatorSite & validatorSites()=0
virtual ManifestCache & validatorManifests()=0
virtual beast::Journal journal(std::string const &name)=0
void addCount(category cat, bool inbound, int bytes)
Account for traffic associated with the given category.
auto const & getCounts() const
An up-to-date copy of all the counters.
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
Json::Value getJson() const
Return JSON representation of configured validator sites.
T count(T... args)
T data(T... args)
T emplace_back(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T find_if(T... args)
T get(T... args)
T is_same_v
T make_tuple(T... args)
@ nullValue
'null' value
Definition json_value.h:19
@ arrayValue
array value (ordered list)
Definition json_value.h:25
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:26
bool is_private(Address const &addr)
Returns true if the address is a private unroutable address.
Definition IPAddress.h:51
Result split_commas(FwdIt first, FwdIt last)
Definition rfc2616.h:177
bool is_keep_alive(boost::beast::http::message< isRequest, Body, Fields > const &m)
Definition rfc2616.h:359
STL namespace.
std::string const & getFullVersionString()
Full server version string.
Definition BuildInfo.cpp:64
@ checkIdlePeers
How often we check for idle peers (seconds)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::vector< ProtocolVersion > parseProtocolVersions(boost::beast::string_view const &value)
Parse a set of protocol versions.
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,...
std::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition chrono.h:94
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:600
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
std::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition Handoff.h:12
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Json::Value getCountsJson(Application &app, int minObjectCount)
Definition GetCounts.cpp:43
void addValidatorManifest(soci::session &session, std::string const &serialized)
addValidatorManifest Saves the manifest of a validator to the database.
Definition Wallet.cpp:94
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition Manifest.cpp:34
beast::xor_shift_engine & default_prng()
Return the default random engine.
@ manifest
Manifest.
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition Number.h:750
std::shared_ptr< Message > makeSquelchMessage(PublicKey const &validator, bool squelch, uint32_t squelchDuration)
Overlay::Setup setup_Overlay(BasicConfig const &config)
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:215
PublicKey verifyHandshake(boost::beast::http::fields const &headers, xrpl::uint256 const &sharedValue, std::optional< std::uint32_t > networkID, beast::IP::Address public_ip, beast::IP::Address remote, Application &app)
Validate header fields necessary for upgrading the link to the peer protocol.
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:791
std::unique_ptr< Overlay > make_Overlay(Application &app, Overlay::Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_context &io_context, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
Creates the implementation of Overlay.
@ accepted
Manifest is valid.
T piecewise_construct
T push_back(T... args)
T shuffle(T... args)
T reserve(T... args)
T reset(T... args)
T setfill(T... args)
T setw(T... args)
T size(T... args)
T str(T... args)
static boost::asio::ip::tcp::endpoint to_asio_endpoint(IP::Endpoint const &address)
static IP::Endpoint from_asio(boost::asio::ip::address const &address)
Used to indicate the result of a server connection handoff.
Definition Handoff.h:18
std::shared_ptr< Writer > response
Definition Handoff.h:27
bool keep_alive
Definition Handoff.h:24
void on_timer(error_code ec)
Timer(OverlayImpl &overlay)
std::uint32_t crawlOptions
Definition Overlay.h:51
std::optional< std::uint32_t > networkID
Definition Overlay.h:52
std::shared_ptr< boost::asio::ssl::context > context
Definition Overlay.h:48
beast::IP::Address public_ip
Definition Overlay.h:49
PeerFinder configuration settings.
static Config makeConfig(xrpl::Config const &config, std::uint16_t port, bool validationPublicKey, int ipLimit)
Make PeerFinder::Config from configuration parameters.
void addMetrics(protocol::MessageType type, std::uint32_t val)
Add protocol message metrics.
Definition TxMetrics.cpp:12
T substr(T... args)
T to_string(T... args)
T what(T... args)