1#include <xrpld/app/consensus/RCLValidations.h>
2#include <xrpld/app/ledger/InboundLedgers.h>
3#include <xrpld/app/ledger/InboundTransactions.h>
4#include <xrpld/app/ledger/LedgerMaster.h>
5#include <xrpld/app/ledger/TransactionMaster.h>
6#include <xrpld/app/misc/HashRouter.h>
7#include <xrpld/app/misc/LoadFeeTrack.h>
8#include <xrpld/app/misc/NetworkOPs.h>
9#include <xrpld/app/misc/Transaction.h>
10#include <xrpld/app/misc/ValidatorList.h>
11#include <xrpld/app/tx/apply.h>
12#include <xrpld/overlay/Cluster.h>
13#include <xrpld/overlay/detail/PeerImp.h>
14#include <xrpld/overlay/detail/Tuning.h>
15#include <xrpld/perflog/PerfLog.h>
17#include <xrpl/basics/UptimeClock.h>
18#include <xrpl/basics/base64.h>
19#include <xrpl/basics/random.h>
20#include <xrpl/basics/safe_cast.h>
21#include <xrpl/protocol/TxFlags.h>
22#include <xrpl/protocol/digest.h>
24#include <boost/algorithm/string/predicate.hpp>
25#include <boost/beast/core/ostream.hpp>
34using namespace std::chrono_literals;
68 , prefix_(makePrefix(fingerprint_))
69 , sink_(app_.journal(
"Peer"), prefix_)
70 , p_sink_(app_.journal(
"Protocol"), prefix_)
73 , stream_ptr_(
std::move(stream_ptr))
74 , socket_(stream_ptr_->next_layer().socket())
75 , stream_(*stream_ptr_)
76 , strand_(
boost::asio::make_strand(socket_.get_executor()))
78 , remote_address_(slot->remote_endpoint())
84 , publicKey_(publicKey)
87 , squelch_(app_.journal(
"Squelch"))
89 , fee_{Resource::feeTrivialPeer,
""}
91 , request_(
std::move(request))
93 , compressionEnabled_(
98 app_.config().COMPRESSION)
104 app_.config().TX_REDUCE_RELAY_ENABLE))
108 app_.config().LEDGER_REPLAY))
109 , ledgerReplayMsgHandler_(app, app.getLedgerReplayer())
113 <<
" vp reduce-relay base squelch enabled "
123 bool const inCluster{
cluster()};
146 if (!
strand_.running_in_this_thread())
149 auto parseLedgerHash =
163 if (
auto const iter =
headers_.find(
"Closed-Ledger");
166 closed = parseLedgerHash(iter->value());
169 fail(
"Malformed handshake data (1)");
172 if (
auto const iter =
headers_.find(
"Previous-Ledger");
175 previous = parseLedgerHash(iter->value());
178 fail(
"Malformed handshake data (2)");
181 if (previous && !closed)
182 fail(
"Malformed handshake data (3)");
204 if (!
strand_.running_in_this_thread())
224 if (!
strand_.running_in_this_thread())
234 auto validator = m->getValidatorKey();
235 if (validator && !
squelch_.expireSquelch(*validator))
245 safe_cast<TrafficCount::category>(m->getCategory()),
266 sink << n <<
" sendq: " << sendq_size;
275 boost::asio::async_write(
284 std::placeholders::_1,
285 std::placeholders::_2)));
291 if (!
strand_.running_in_this_thread())
297 protocol::TMHaveTransactions ht;
299 ht.add_hashes(hash.data(), hash.size());
310 if (!
strand_.running_in_this_thread())
327 if (!
strand_.running_in_this_thread())
332 auto removed =
txQueue_.erase(hash);
344 fail(
"charge: Resources");
353 auto const iter =
headers_.find(
"Crawl");
356 return boost::iequals(iter->value(),
"public");
382 ret[jss::inbound] =
true;
386 ret[jss::cluster] =
true;
396 if (
auto const nid =
headers_[
"Network-ID"]; !nid.empty())
413 std::chrono::duration_cast<std::chrono::seconds>(
uptime()).count());
418 if ((minSeq != 0) || (maxSeq != 0))
419 ret[jss::complete_ledgers] =
425 ret[jss::track] =
"diverged";
429 ret[jss::track] =
"unknown";
438 protocol::TMStatusChange last_status;
445 if (closedLedgerHash != beast::zero)
446 ret[jss::ledger] =
to_string(closedLedgerHash);
448 if (last_status.has_newstatus())
450 switch (last_status.newstatus())
452 case protocol::nsCONNECTING:
453 ret[jss::status] =
"connecting";
456 case protocol::nsCONNECTED:
457 ret[jss::status] =
"connected";
460 case protocol::nsMONITORING:
461 ret[jss::status] =
"monitoring";
464 case protocol::nsVALIDATING:
465 ret[jss::status] =
"validating";
468 case protocol::nsSHUTTING:
469 ret[jss::status] =
"shutting";
474 <<
"Unknown status: " << last_status.newstatus();
479 ret[jss::metrics][jss::total_bytes_recv] =
481 ret[jss::metrics][jss::total_bytes_sent] =
483 ret[jss::metrics][jss::avg_bps_recv] =
485 ret[jss::metrics][jss::avg_bps_sent] =
564 strand_.running_in_this_thread(),
565 "ripple::PeerImp::fail : strand in this thread");
578 if (!
strand_.running_in_this_thread())
603 strand_.running_in_this_thread(),
604 "ripple::PeerImp::tryAsyncShutdown : strand in this thread");
617 stream_.async_shutdown(bind_executor(
627 strand_.running_in_this_thread(),
628 "ripple::PeerImp::shutdown: strand in this thread");
635 boost::beast::get_lowest_layer(
stream_).cancel();
652 (ec != boost::asio::error::eof &&
653 ec != boost::asio::error::operation_aborted &&
654 ec.message().find(
"application data after close notify") ==
670 strand_.running_in_this_thread(),
671 "ripple::PeerImp::close : strand in this thread");
697 timer_.expires_after(interval);
705 timer_.async_wait(bind_executor(
725 strand_.running_in_this_thread(),
726 "ripple::PeerImp::onTimer : strand in this thread");
734 if (ec == boost::asio::error::operation_aborted)
751 return fail(
"Large send queue");
755 clock_type::duration duration;
768 return fail(
"Not useful");
774 return fail(
"Ping Timeout");
779 protocol::TMPing message;
780 message.set_type(protocol::TMPing::ptPING);
807 "ripple::PeerImp::doAccept : empty read buffer");
820 return fail(
"makeSharedValue: Unexpected failure");
852 boost::asio::async_write(
854 write_buffer->data(),
855 boost::asio::transfer_all(),
862 if (ec == boost::asio::error::operation_aborted)
865 return fail(
"onWriteResponse", ec);
866 if (write_buffer->size() == bytes_transferred)
868 return fail(
"Failed to write header");
935 strand_.running_in_this_thread(),
936 "ripple::PeerImp::onReadMessage : strand in this thread");
945 if (ec == boost::asio::error::eof)
951 if (ec == boost::asio::error::operation_aborted)
954 return fail(
"onReadMessage", ec);
962 stream <<
"onReadMessage: "
963 << (bytes_transferred > 0
964 ?
to_string(bytes_transferred) +
" bytes"
968 metrics_.recv.add_message(bytes_transferred);
978 using namespace std::chrono_literals;
983 "invokeProtocolMessage",
993 return fail(
"onReadMessage", ec);
995 if (bytes_consumed == 0)
1018 std::placeholders::_1,
1019 std::placeholders::_2)));
1026 strand_.running_in_this_thread(),
1027 "ripple::PeerImp::onWriteMessage : strand in this thread");
1036 if (ec == boost::asio::error::operation_aborted)
1039 return fail(
"onWriteMessage", ec);
1044 stream <<
"onWriteMessage: "
1045 << (bytes_transferred > 0
1046 ?
to_string(bytes_transferred) +
" bytes"
1050 metrics_.sent.add_message(bytes_transferred);
1054 "ripple::PeerImp::onWriteMessage : non-empty send buffer");
1065 "ripple::PeerImp::onWriteMessage : shutdown started");
1068 return boost::asio::async_write(
1070 boost::asio::buffer(
1077 std::placeholders::_1,
1078 std::placeholders::_2)));
1107 *m,
static_cast<protocol::MessageType
>(type),
true);
1117 if ((type == MessageType::mtTRANSACTION ||
1118 type == MessageType::mtHAVE_TRANSACTIONS ||
1119 type == MessageType::mtTRANSACTIONS ||
1131 static_cast<MessageType
>(type),
static_cast<std::uint64_t>(size));
1133 JLOG(
journal_.
trace()) <<
"onMessageBegin: " << type <<
" " << size <<
" "
1134 << uncompressed_size <<
" " << isCompressed;
1149 auto const s = m->list_size();
1169 if (m->type() == protocol::TMPing::ptPING)
1173 m->set_type(protocol::TMPing::ptPONG);
1178 if (m->type() == protocol::TMPing::ptPONG && m->has_seq())
1188 auto const rtt = std::chrono::round<std::chrono::milliseconds>(
1213 for (
int i = 0; i < m->clusternodes().size(); ++i)
1215 protocol::TMClusterNode
const& node = m->clusternodes(i);
1218 if (node.has_nodename())
1219 name = node.nodename();
1221 auto const publicKey =
1228 auto const reportTime =
1232 *publicKey,
name, node.nodeload(), reportTime);
1236 int loadSources = m->loadsources().size();
1237 if (loadSources != 0)
1240 gossip.
items.reserve(loadSources);
1241 for (
int i = 0; i < m->loadsources().size(); ++i)
1243 protocol::TMLoadSource
const& node = m->loadsources(i);
1248 gossip.
items.push_back(item);
1261 if (status.getReportTime() >= thresh)
1262 fees.push_back(status.getLoadFee());
1267 auto const index = fees.size() / 2;
1269 clusterFee = fees[index];
1285 if (m->endpoints_v2().size() >= 1024)
1292 endpoints.
reserve(m->endpoints_v2().size());
1295 for (
auto const& tm : m->endpoints_v2())
1302 << tm.endpoint() <<
"}";
1328 if (!endpoints.
empty())
1345 eraseTxQueue !=
batch,
1346 (
"ripple::PeerImp::handleTransaction : valid inputs"));
1355 <<
"Need network ledger";
1364 uint256 txID = stx->getTransactionID();
1371 JLOG(
p_journal_.
warn()) <<
"Ignoring Network relayed Tx containing "
1372 "tfInnerBatchTxn (handleTransaction).";
1404 bool checkSignature =
true;
1407 if (!m->has_deferred() || !m->deferred())
1420 checkSignature =
false;
1427 <<
"No new transactions until synchronized";
1440 "recvTransaction->checkTransaction",
1446 if (
auto peer = weak.lock())
1447 peer->checkTransaction(
1448 flags, checkSignature, stx,
batch);
1455 <<
"Transaction invalid: " <<
strHex(m->rawtransaction())
1456 <<
". Exception: " << ex.
what();
1467 auto const itype{m->itype()};
1470 if (itype < protocol::liBASE || itype > protocol::liTS_CANDIDATE)
1471 return badData(
"Invalid ledger info type");
1479 if (itype == protocol::liTS_CANDIDATE)
1481 if (!m->has_ledgerhash())
1482 return badData(
"Invalid TX candidate set, missing TX set hash");
1485 !m->has_ledgerhash() && !m->has_ledgerseq() &&
1486 !(ltype && *ltype == protocol::ltCLOSED))
1488 return badData(
"Invalid request");
1492 if (ltype && (*ltype < protocol::ltACCEPTED || *ltype > protocol::ltCLOSED))
1493 return badData(
"Invalid ledger type");
1497 return badData(
"Invalid ledger hash");
1500 if (m->has_ledgerseq())
1502 auto const ledgerSeq{m->ledgerseq()};
1505 using namespace std::chrono_literals;
1515 if (itype != protocol::liBASE)
1517 if (m->nodeids_size() <= 0)
1518 return badData(
"Invalid ledger node IDs");
1520 for (
auto const& nodeId : m->nodeids())
1523 return badData(
"Invalid SHAMap node ID");
1528 if (m->has_querytype() && m->querytype() != protocol::qtINDIRECT)
1529 return badData(
"Invalid query type");
1532 if (m->has_querydepth())
1535 itype == protocol::liBASE)
1537 return badData(
"Invalid query depth");
1544 if (
auto peer = weak.
lock())
1545 peer->processLedgerRequest(m);
1565 if (
auto peer = weak.
lock())
1568 peer->ledgerReplayMsgHandler_.processProofPathRequest(m);
1569 if (reply.has_error())
1571 if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1573 Resource::feeMalformedRequest,
1574 "proof_path_request");
1577 Resource::feeRequestNoReply,
"proof_path_request");
1581 peer->send(std::make_shared<Message>(
1582 reply, protocol::mtPROOF_PATH_RESPONSE));
1591 if (!ledgerReplayEnabled_)
1594 Resource::feeMalformedRequest,
"proof_path_response disabled");
1598 if (!ledgerReplayMsgHandler_.processProofPathResponse(m))
1600 fee_.update(Resource::feeInvalidData,
"proof_path_response");
1607 JLOG(p_journal_.trace()) <<
"onMessage, TMReplayDeltaRequest";
1608 if (!ledgerReplayEnabled_)
1611 Resource::feeMalformedRequest,
"replay_delta_request disabled");
1615 fee_.fee = Resource::feeModerateBurdenPeer;
1617 app_.getJobQueue().addJob(
1619 if (
auto peer = weak.
lock())
1622 peer->ledgerReplayMsgHandler_.processReplayDeltaRequest(m);
1623 if (reply.has_error())
1625 if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1627 Resource::feeMalformedRequest,
1628 "replay_delta_request");
1631 Resource::feeRequestNoReply,
1632 "replay_delta_request");
1636 peer->send(std::make_shared<Message>(
1637 reply, protocol::mtREPLAY_DELTA_RESPONSE));
1646 if (!ledgerReplayEnabled_)
1649 Resource::feeMalformedRequest,
"replay_delta_response disabled");
1653 if (!ledgerReplayMsgHandler_.processReplayDeltaResponse(m))
1655 fee_.update(Resource::feeInvalidData,
"replay_delta_response");
1663 fee_.update(Resource::feeInvalidData, msg);
1664 JLOG(p_journal_.warn()) <<
"TMLedgerData: " << msg;
1669 return badData(
"Invalid ledger hash");
1673 auto const ledgerSeq{m->ledgerseq()};
1674 if (m->type() == protocol::liTS_CANDIDATE)
1685 using namespace std::chrono_literals;
1686 if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s &&
1687 ledgerSeq > app_.getLedgerMaster().getValidLedgerIndex() + 10)
1696 if (m->type() < protocol::liBASE || m->type() > protocol::liTS_CANDIDATE)
1697 return badData(
"Invalid ledger info type");
1700 if (m->has_error() &&
1701 (m->error() < protocol::reNO_LEDGER ||
1702 m->error() > protocol::reBAD_REQUEST))
1704 return badData(
"Invalid reply error");
1708 if (m->nodes_size() <= 0 || m->nodes_size() > Tuning::hardMaxReplyNodes)
1711 "Invalid Ledger/TXset nodes " +
std::to_string(m->nodes_size()));
1715 if (m->has_requestcookie())
1717 if (
auto peer = overlay_.findPeerByShortID(m->requestcookie()))
1719 m->clear_requestcookie();
1724 JLOG(p_journal_.info()) <<
"Unable to route TX/ledger data reply";
1729 uint256 const ledgerHash{m->ledgerhash()};
1732 if (m->type() == protocol::liTS_CANDIDATE)
1735 app_.getJobQueue().addJob(
1736 jtTXN_DATA,
"recvPeerData", [weak, ledgerHash, m]() {
1737 if (
auto peer = weak.lock())
1739 peer->app_.getInboundTransactions().gotData(
1740 ledgerHash, peer, m);
1747 app_.getInboundLedgers().gotLedgerData(ledgerHash, shared_from_this(), m);
1753 protocol::TMProposeSet&
set = *m;
1762 JLOG(p_journal_.warn()) <<
"Proposal: malformed";
1764 Resource::feeInvalidSignature,
1765 " signature can't be longer than 72 bytes");
1772 JLOG(p_journal_.warn()) <<
"Proposal: malformed";
1773 fee_.update(Resource::feeMalformedRequest,
"bad hashes");
1781 auto const isTrusted = app_.validators().trusted(publicKey);
1789 overlay_.reportInboundTraffic(
1790 TrafficCount::category::proposal_untrusted,
1791 Message::messageSize(*m));
1793 if (app_.config().RELAY_UNTRUSTED_PROPOSALS == -1)
1797 uint256 const proposeHash{
set.currenttxhash()};
1798 uint256 const prevLedger{
set.previousledger()};
1810 if (
auto [added, relayed] =
1811 app_.getHashRouter().addSuppressionPeerWithStatus(suppression, id_);
1816 if (relayed && (
stopwatch().now() - *relayed) < reduce_relay::IDLED)
1817 overlay_.updateSlotAndSquelch(
1818 suppression, publicKey, id_, protocol::mtPROPOSE_LEDGER);
1821 overlay_.reportInboundTraffic(
1822 TrafficCount::category::proposal_duplicate,
1823 Message::messageSize(*m));
1825 JLOG(p_journal_.trace()) <<
"Proposal: duplicate";
1832 if (tracking_.load() == Tracking::diverged)
1834 JLOG(p_journal_.debug())
1835 <<
"Proposal: Dropping untrusted (peer divergence)";
1839 if (!cluster() && app_.getFeeTrack().isLoadedLocal())
1841 JLOG(p_journal_.debug()) <<
"Proposal: Dropping untrusted (load)";
1846 JLOG(p_journal_.trace())
1847 <<
"Proposal: " << (isTrusted ?
"trusted" :
"untrusted");
1858 app_.timeKeeper().closeTime(),
1859 calcNodeID(app_.validatorManifests().getMasterKey(publicKey))});
1862 app_.getJobQueue().addJob(
1864 "recvPropose->checkPropose",
1866 if (
auto peer = weak.lock())
1867 peer->checkPropose(isTrusted, m,
proposal);
1874 JLOG(p_journal_.trace()) <<
"Status: Change";
1876 if (!m->has_networktime())
1877 m->set_networktime(app_.timeKeeper().now().time_since_epoch().count());
1881 if (!last_status_.has_newstatus() || m->has_newstatus())
1886 protocol::NodeStatus status = last_status_.newstatus();
1888 m->set_newstatus(status);
1892 if (m->newevent() == protocol::neLOST_SYNC)
1894 bool outOfSync{
false};
1899 if (!closedLedgerHash_.isZero())
1902 closedLedgerHash_.zero();
1904 previousLedgerHash_.zero();
1908 JLOG(p_journal_.debug()) <<
"Status: Out of sync";
1915 bool const peerChangedLedgers{
1922 if (peerChangedLedgers)
1924 closedLedgerHash_ = m->ledgerhash();
1925 closedLedgerHash = closedLedgerHash_;
1926 addLedger(closedLedgerHash, sl);
1930 closedLedgerHash_.zero();
1933 if (m->has_ledgerhashprevious() &&
1936 previousLedgerHash_ = m->ledgerhashprevious();
1937 addLedger(previousLedgerHash_, sl);
1941 previousLedgerHash_.zero();
1944 if (peerChangedLedgers)
1946 JLOG(p_journal_.debug()) <<
"LCL is " << closedLedgerHash;
1950 JLOG(p_journal_.debug()) <<
"Status: No ledger";
1954 if (m->has_firstseq() && m->has_lastseq())
1958 minLedger_ = m->firstseq();
1959 maxLedger_ = m->lastseq();
1961 if ((maxLedger_ < minLedger_) || (minLedger_ == 0) || (maxLedger_ == 0))
1962 minLedger_ = maxLedger_ = 0;
1965 if (m->has_ledgerseq() &&
1966 app_.getLedgerMaster().getValidatedLedgerAge() < 2min)
1969 m->ledgerseq(), app_.getLedgerMaster().getValidLedgerIndex());
1972 app_.getOPs().pubPeerStatus([=,
this]() ->
Json::Value {
1975 if (m->has_newstatus())
1977 switch (m->newstatus())
1979 case protocol::nsCONNECTING:
1980 j[jss::status] =
"CONNECTING";
1982 case protocol::nsCONNECTED:
1983 j[jss::status] =
"CONNECTED";
1985 case protocol::nsMONITORING:
1986 j[jss::status] =
"MONITORING";
1988 case protocol::nsVALIDATING:
1989 j[jss::status] =
"VALIDATING";
1991 case protocol::nsSHUTTING:
1992 j[jss::status] =
"SHUTTING";
1997 if (m->has_newevent())
1999 switch (m->newevent())
2001 case protocol::neCLOSING_LEDGER:
2002 j[jss::action] =
"CLOSING_LEDGER";
2004 case protocol::neACCEPTED_LEDGER:
2005 j[jss::action] =
"ACCEPTED_LEDGER";
2007 case protocol::neSWITCHED_LEDGER:
2008 j[jss::action] =
"SWITCHED_LEDGER";
2010 case protocol::neLOST_SYNC:
2011 j[jss::action] =
"LOST_SYNC";
2016 if (m->has_ledgerseq())
2018 j[jss::ledger_index] = m->ledgerseq();
2021 if (m->has_ledgerhash())
2023 uint256 closedLedgerHash{};
2026 closedLedgerHash = closedLedgerHash_;
2028 j[jss::ledger_hash] = to_string(closedLedgerHash);
2031 if (m->has_networktime())
2036 if (m->has_firstseq() && m->has_lastseq())
2038 j[jss::ledger_index_min] =
Json::UInt(m->firstseq());
2039 j[jss::ledger_index_max] =
Json::UInt(m->lastseq());
2055 serverSeq = maxLedger_;
2061 checkTracking(serverSeq, validationSeq);
2070 if (diff < Tuning::convergedLedgerLimit)
2073 tracking_ = Tracking::converged;
2076 if ((diff > Tuning::divergedLedgerLimit) &&
2077 (tracking_.load() != Tracking::diverged))
2082 tracking_ = Tracking::diverged;
2083 trackingTime_ = clock_type::now();
2092 fee_.update(Resource::feeMalformedRequest,
"bad hash");
2096 uint256 const hash{m->hash()};
2098 if (m->status() == protocol::tsHAVE)
2102 if (
std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
2103 recentTxSets_.end())
2105 fee_.update(Resource::feeUselessData,
"duplicate (tsHAVE)");
2109 recentTxSets_.push_back(hash);
2114PeerImp::onValidatorListMessage(
2124 JLOG(p_journal_.warn()) <<
"Ignored malformed " << messageType;
2126 fee_.update(Resource::feeHeavyBurdenPeer,
"no blobs");
2132 JLOG(p_journal_.debug()) <<
"Received " << messageType;
2134 if (!app_.getHashRouter().addSuppressionPeer(hash, id_))
2136 JLOG(p_journal_.debug())
2137 << messageType <<
": received duplicate " << messageType;
2141 fee_.update(Resource::feeUselessData,
"duplicate");
2145 auto const applyResult = app_.validators().applyListsAndBroadcast(
2149 remote_address_.to_string(),
2152 app_.getHashRouter(),
2155 JLOG(p_journal_.debug())
2156 <<
"Processed " << messageType <<
" version " << version <<
" from "
2157 << (applyResult.publisherKey ?
strHex(*applyResult.publisherKey)
2158 :
"unknown or invalid publisher")
2159 <<
" with best result " << to_string(applyResult.bestDisposition());
2162 switch (applyResult.bestDisposition())
2165 case ListDisposition::accepted:
2167 case ListDisposition::expired:
2169 case ListDisposition::pending: {
2173 applyResult.publisherKey,
2174 "ripple::PeerImp::onValidatorListMessage : publisher key is "
2176 auto const& pubKey = *applyResult.publisherKey;
2178 if (
auto const iter = publisherListSequences_.find(pubKey);
2179 iter != publisherListSequences_.end())
2182 iter->second < applyResult.sequence,
2183 "ripple::PeerImp::onValidatorListMessage : lower sequence");
2186 publisherListSequences_[pubKey] = applyResult.sequence;
2189 case ListDisposition::same_sequence:
2190 case ListDisposition::known_sequence:
2195 applyResult.sequence && applyResult.publisherKey,
2196 "ripple::PeerImp::onValidatorListMessage : nonzero sequence "
2197 "and set publisher key");
2199 publisherListSequences_[*applyResult.publisherKey] <=
2200 applyResult.sequence,
2201 "ripple::PeerImp::onValidatorListMessage : maximum sequence");
2206 case ListDisposition::stale:
2207 case ListDisposition::untrusted:
2208 case ListDisposition::invalid:
2209 case ListDisposition::unsupported_version:
2214 "ripple::PeerImp::onValidatorListMessage : invalid best list "
2220 switch (applyResult.worstDisposition())
2222 case ListDisposition::accepted:
2223 case ListDisposition::expired:
2224 case ListDisposition::pending:
2227 case ListDisposition::same_sequence:
2228 case ListDisposition::known_sequence:
2233 Resource::feeUselessData,
2234 " duplicate (same_sequence or known_sequence)");
2236 case ListDisposition::stale:
2239 fee_.update(Resource::feeInvalidData,
"expired");
2241 case ListDisposition::untrusted:
2245 fee_.update(Resource::feeUselessData,
"untrusted");
2247 case ListDisposition::invalid:
2250 Resource::feeInvalidSignature,
"invalid list disposition");
2252 case ListDisposition::unsupported_version:
2255 fee_.update(Resource::feeInvalidData,
"version");
2260 "ripple::PeerImp::onValidatorListMessage : invalid worst list "
2266 for (
auto const& [disp, count] : applyResult.dispositions)
2271 case ListDisposition::accepted:
2272 JLOG(p_journal_.debug())
2273 <<
"Applied " << count <<
" new " << messageType;
2276 case ListDisposition::expired:
2277 JLOG(p_journal_.debug())
2278 <<
"Applied " << count <<
" expired " << messageType;
2281 case ListDisposition::pending:
2282 JLOG(p_journal_.debug())
2283 <<
"Processed " << count <<
" future " << messageType;
2285 case ListDisposition::same_sequence:
2286 JLOG(p_journal_.warn())
2287 <<
"Ignored " << count <<
" " << messageType
2288 <<
"(s) with current sequence";
2290 case ListDisposition::known_sequence:
2291 JLOG(p_journal_.warn())
2292 <<
"Ignored " << count <<
" " << messageType
2293 <<
"(s) with future sequence";
2295 case ListDisposition::stale:
2296 JLOG(p_journal_.warn())
2297 <<
"Ignored " << count <<
"stale " << messageType;
2299 case ListDisposition::untrusted:
2300 JLOG(p_journal_.warn())
2301 <<
"Ignored " << count <<
" untrusted " << messageType;
2303 case ListDisposition::unsupported_version:
2304 JLOG(p_journal_.warn())
2305 <<
"Ignored " << count <<
"unsupported version "
2308 case ListDisposition::invalid:
2309 JLOG(p_journal_.warn())
2310 <<
"Ignored " << count <<
"invalid " << messageType;
2315 "ripple::PeerImp::onValidatorListMessage : invalid list "
2327 if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
2329 JLOG(p_journal_.debug())
2330 <<
"ValidatorList: received validator list from peer using "
2331 <<
"protocol version " << to_string(protocol_)
2332 <<
" which shouldn't support this feature.";
2333 fee_.update(Resource::feeUselessData,
"unsupported peer");
2336 onValidatorListMessage(
2340 ValidatorList::parseBlobs(*m));
2344 JLOG(p_journal_.warn()) <<
"ValidatorList: Exception, " << e.
what();
2345 using namespace std::string_literals;
2346 fee_.update(Resource::feeInvalidData, e.
what());
2356 if (!supportsFeature(ProtocolFeature::ValidatorList2Propagation))
2358 JLOG(p_journal_.debug())
2359 <<
"ValidatorListCollection: received validator list from peer "
2360 <<
"using protocol version " << to_string(protocol_)
2361 <<
" which shouldn't support this feature.";
2362 fee_.update(Resource::feeUselessData,
"unsupported peer");
2365 else if (m->version() < 2)
2367 JLOG(p_journal_.debug())
2368 <<
"ValidatorListCollection: received invalid validator list "
2370 << m->version() <<
" from peer using protocol version "
2371 << to_string(protocol_);
2372 fee_.update(Resource::feeInvalidData,
"wrong version");
2375 onValidatorListMessage(
2376 "ValidatorListCollection",
2379 ValidatorList::parseBlobs(*m));
2383 JLOG(p_journal_.warn())
2384 <<
"ValidatorListCollection: Exception, " << e.
what();
2385 using namespace std::string_literals;
2386 fee_.update(Resource::feeInvalidData, e.
what());
2393 if (m->validation().size() < 50)
2395 JLOG(p_journal_.warn()) <<
"Validation: Too small";
2396 fee_.update(Resource::feeMalformedRequest,
"too small");
2402 auto const closeTime = app_.timeKeeper().closeTime();
2411 app_.validatorManifests().getMasterKey(pk));
2414 val->setSeen(closeTime);
2418 app_.getValidations().parms(),
2419 app_.timeKeeper().closeTime(),
2421 val->getSeenTime()))
2423 JLOG(p_journal_.trace()) <<
"Validation: Not current";
2424 fee_.update(Resource::feeUselessData,
"not current");
2431 auto const isTrusted =
2432 app_.validators().trusted(val->getSignerPublic());
2440 overlay_.reportInboundTraffic(
2441 TrafficCount::category::validation_untrusted,
2442 Message::messageSize(*m));
2444 if (app_.config().RELAY_UNTRUSTED_VALIDATIONS == -1)
2450 auto [added, relayed] =
2451 app_.getHashRouter().addSuppressionPeerWithStatus(key, id_);
2458 if (relayed && (
stopwatch().now() - *relayed) < reduce_relay::IDLED)
2459 overlay_.updateSlotAndSquelch(
2460 key, val->getSignerPublic(), id_, protocol::mtVALIDATION);
2463 overlay_.reportInboundTraffic(
2464 TrafficCount::category::validation_duplicate,
2465 Message::messageSize(*m));
2467 JLOG(p_journal_.trace()) <<
"Validation: duplicate";
2471 if (!isTrusted && (tracking_.load() == Tracking::diverged))
2473 JLOG(p_journal_.debug())
2474 <<
"Dropping untrusted validation from diverged peer";
2476 else if (isTrusted || !app_.getFeeTrack().isLoadedLocal())
2480 isTrusted ?
"Trusted validation" :
"Untrusted validation";
2485 to_string(val->getNodeID());
2492 app_.getJobQueue().addJob(
2495 [weak, val, m, key]() {
2496 if (
auto peer = weak.
lock())
2497 peer->checkValidation(val, key, m);
2502 JLOG(p_journal_.debug())
2503 <<
"Dropping untrusted validation for load";
2508 JLOG(p_journal_.warn())
2509 <<
"Exception processing validation: " << e.
what();
2510 using namespace std::string_literals;
2511 fee_.update(Resource::feeMalformedRequest, e.
what());
2518 protocol::TMGetObjectByHash& packet = *m;
2520 JLOG(p_journal_.trace()) <<
"received TMGetObjectByHash " << packet.type()
2521 <<
" " << packet.objects_size();
2526 if (send_queue_.size() >= Tuning::dropSendQueue)
2528 JLOG(p_journal_.debug()) <<
"GetObject: Large send queue";
2532 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2538 if (packet.type() == protocol::TMGetObjectByHash::otTRANSACTIONS)
2540 if (!txReduceRelayEnabled())
2542 JLOG(p_journal_.error())
2543 <<
"TMGetObjectByHash: tx reduce-relay is disabled";
2544 fee_.update(Resource::feeMalformedRequest,
"disabled");
2549 app_.getJobQueue().addJob(
2551 if (
auto peer = weak.
lock())
2552 peer->doTransactions(m);
2557 protocol::TMGetObjectByHash reply;
2559 reply.set_query(
false);
2561 if (packet.has_seq())
2562 reply.set_seq(packet.seq());
2564 reply.set_type(packet.type());
2566 if (packet.has_ledgerhash())
2570 fee_.update(Resource::feeMalformedRequest,
"ledger hash");
2574 reply.set_ledgerhash(packet.ledgerhash());
2578 Resource::feeModerateBurdenPeer,
2579 " received a get object by hash request");
2582 for (
int i = 0; i < packet.objects_size(); ++i)
2584 auto const& obj = packet.objects(i);
2587 uint256 const hash{obj.hash()};
2590 std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2591 auto nodeObject{app_.getNodeStore().fetchNodeObject(hash, seq)};
2594 protocol::TMIndexedObject& newObj = *reply.add_objects();
2595 newObj.set_hash(hash.begin(), hash.size());
2597 &nodeObject->getData().front(),
2598 nodeObject->getData().size());
2600 if (obj.has_nodeid())
2601 newObj.set_index(obj.nodeid());
2602 if (obj.has_ledgerseq())
2603 newObj.set_ledgerseq(obj.ledgerseq());
2610 JLOG(p_journal_.trace()) <<
"GetObj: " << reply.objects_size() <<
" of "
2611 << packet.objects_size();
2619 bool progress =
false;
2621 for (
int i = 0; i < packet.objects_size(); ++i)
2623 protocol::TMIndexedObject
const& obj = packet.objects(i);
2627 if (obj.has_ledgerseq())
2629 if (obj.ledgerseq() != pLSeq)
2631 if (pLDo && (pLSeq != 0))
2633 JLOG(p_journal_.debug())
2634 <<
"GetObj: Full fetch pack for " << pLSeq;
2636 pLSeq = obj.ledgerseq();
2637 pLDo = !app_.getLedgerMaster().haveLedger(pLSeq);
2641 JLOG(p_journal_.debug())
2642 <<
"GetObj: Late fetch pack for " << pLSeq;
2651 uint256 const hash{obj.hash()};
2653 app_.getLedgerMaster().addFetchPack(
2656 obj.data().begin(), obj.data().end()));
2661 if (pLDo && (pLSeq != 0))
2663 JLOG(p_journal_.debug())
2664 <<
"GetObj: Partial fetch pack for " << pLSeq;
2666 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2667 app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2674 if (!txReduceRelayEnabled())
2676 JLOG(p_journal_.error())
2677 <<
"TMHaveTransactions: tx reduce-relay is disabled";
2678 fee_.update(Resource::feeMalformedRequest,
"disabled");
2683 app_.getJobQueue().addJob(
2685 if (
auto peer = weak.
lock())
2686 peer->handleHaveTransactions(m);
2691PeerImp::handleHaveTransactions(
2694 protocol::TMGetObjectByHash tmBH;
2695 tmBH.set_type(protocol::TMGetObjectByHash_ObjectType_otTRANSACTIONS);
2696 tmBH.set_query(
true);
2698 JLOG(p_journal_.trace())
2699 <<
"received TMHaveTransactions " << m->hashes_size();
2705 JLOG(p_journal_.error())
2706 <<
"TMHaveTransactions with invalid hash size";
2707 fee_.update(Resource::feeMalformedRequest,
"hash size");
2713 auto txn = app_.getMasterTransaction().fetch_from_cache(hash);
2715 JLOG(p_journal_.trace()) <<
"checking transaction " << (bool)txn;
2719 JLOG(p_journal_.debug()) <<
"adding transaction to request";
2721 auto obj = tmBH.add_objects();
2722 obj->set_hash(hash.
data(), hash.
size());
2729 removeTxQueue(hash);
2733 JLOG(p_journal_.trace())
2734 <<
"transaction request object is " << tmBH.objects_size();
2736 if (tmBH.objects_size() > 0)
2743 if (!txReduceRelayEnabled())
2745 JLOG(p_journal_.error())
2746 <<
"TMTransactions: tx reduce-relay is disabled";
2747 fee_.update(Resource::feeMalformedRequest,
"disabled");
2751 JLOG(p_journal_.trace())
2752 <<
"received TMTransactions " << m->transactions_size();
2754 overlay_.addTxMetrics(m->transactions_size());
2759 m->mutable_transactions(i), [](protocol::TMTransaction*) {}),
2767 using on_message_fn =
2769 if (!strand_.running_in_this_thread())
2773 (on_message_fn)&PeerImp::onMessage, shared_from_this(), m));
2775 if (!m->has_validatorpubkey())
2777 fee_.update(Resource::feeInvalidData,
"squelch no pubkey");
2780 auto validator = m->validatorpubkey();
2784 fee_.update(Resource::feeInvalidData,
"squelch bad pubkey");
2790 if (key == app_.getValidationPublicKey())
2792 JLOG(p_journal_.debug())
2793 <<
"onMessage: TMSquelch discarding validator's squelch " << slice;
2798 m->has_squelchduration() ? m->squelchduration() : 0;
2800 squelch_.removeSquelch(key);
2802 fee_.update(Resource::feeInvalidData,
"squelch duration");
2804 JLOG(p_journal_.debug())
2805 <<
"onMessage: TMSquelch " << slice <<
" " << id() <<
" " << duration;
2817 (void)lockedRecentLock;
2819 if (
std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
2820 recentLedgers_.end())
2823 recentLedgers_.push_back(hash);
2832 if (app_.getFeeTrack().isLoadedLocal() ||
2833 (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2834 (app_.getJobQueue().getJobCount(
jtPACK) > 10))
2836 JLOG(p_journal_.info()) <<
"Too busy to make fetch pack";
2842 JLOG(p_journal_.warn()) <<
"FetchPack hash size malformed";
2843 fee_.update(Resource::feeMalformedRequest,
"hash size");
2847 fee_.fee = Resource::feeHeavyBurdenPeer;
2849 uint256 const hash{packet->ledgerhash()};
2852 auto elapsed = UptimeClock::now();
2853 auto const pap = &app_;
2854 app_.getJobQueue().addJob(
2855 jtPACK,
"MakeFetchPack", [pap, weak, packet, hash, elapsed]() {
2856 pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
2861PeerImp::doTransactions(
2864 protocol::TMTransactions reply;
2866 JLOG(p_journal_.trace()) <<
"received TMGetObjectByHash requesting tx "
2867 << packet->objects_size();
2869 if (packet->objects_size() > reduce_relay::MAX_TX_QUEUE_SIZE)
2871 JLOG(p_journal_.error()) <<
"doTransactions, invalid number of hashes";
2872 fee_.update(Resource::feeMalformedRequest,
"too big");
2878 auto const& obj = packet->objects(i);
2882 fee_.update(Resource::feeMalformedRequest,
"hash size");
2888 auto txn = app_.getMasterTransaction().fetch_from_cache(hash);
2892 JLOG(p_journal_.error()) <<
"doTransactions, transaction not found "
2894 fee_.update(Resource::feeMalformedRequest,
"tx not found");
2899 auto tx = reply.add_transactions();
2900 auto sttx = txn->getSTransaction();
2902 tx->set_rawtransaction(s.
data(), s.
size());
2904 txn->getStatus() ==
INCLUDED ? protocol::tsCURRENT
2906 tx->set_receivetimestamp(
2907 app_.timeKeeper().now().time_since_epoch().count());
2908 tx->set_deferred(txn->getSubmitResult().queued);
2911 if (reply.transactions_size() > 0)
2916PeerImp::checkTransaction(
2918 bool checkSignature,
2930 JLOG(p_journal_.warn()) <<
"Ignoring Network relayed Tx containing "
2931 "tfInnerBatchTxn (checkSignature).";
2932 charge(Resource::feeModerateBurdenPeer,
"inner batch txn");
2938 if (stx->isFieldPresent(sfLastLedgerSequence) &&
2939 (stx->getFieldU32(sfLastLedgerSequence) <
2940 app_.getLedgerMaster().getValidLedgerIndex()))
2942 JLOG(p_journal_.info())
2943 <<
"Marking transaction " << stx->getTransactionID()
2944 <<
"as BAD because it's expired";
2945 app_.getHashRouter().setFlags(
2946 stx->getTransactionID(), HashRouterFlags::BAD);
2947 charge(Resource::feeUselessData,
"expired tx");
2958 tx->getStatus() ==
NEW,
2959 "ripple::PeerImp::checkTransaction Transaction created "
2961 if (tx->getStatus() ==
NEW)
2963 JLOG(p_journal_.debug())
2964 <<
"Processing " << (
batch ?
"batch" :
"unsolicited")
2965 <<
" pseudo-transaction tx " << tx->getID();
2967 app_.getMasterTransaction().canonicalize(&tx);
2970 app_.getHashRouter().shouldRelay(tx->getID());
2973 JLOG(p_journal_.debug())
2974 <<
"Passing skipped pseudo pseudo-transaction tx "
2976 app_.overlay().relay(tx->getID(), {}, *toSkip);
2980 JLOG(p_journal_.debug())
2981 <<
"Charging for pseudo-transaction tx " << tx->getID();
2982 charge(Resource::feeUselessData,
"pseudo tx");
2993 app_.getHashRouter(),
2995 app_.getLedgerMaster().getValidatedRules(),
2997 valid != Validity::Valid)
2999 if (!validReason.empty())
3001 JLOG(p_journal_.debug())
3002 <<
"Exception checking transaction: " << validReason;
3007 app_.getHashRouter().setFlags(
3008 stx->getTransactionID(), HashRouterFlags::BAD);
3010 Resource::feeInvalidSignature,
3011 "check transaction signature failure");
3018 app_.getHashRouter(), stx->getTransactionID(), Validity::Valid);
3024 if (tx->getStatus() ==
INVALID)
3026 if (!reason.
empty())
3028 JLOG(p_journal_.debug())
3029 <<
"Exception checking transaction: " << reason;
3031 app_.getHashRouter().setFlags(
3032 stx->getTransactionID(), HashRouterFlags::BAD);
3033 charge(Resource::feeInvalidSignature,
"tx (impossible)");
3037 bool const trusted = any(flags & HashRouterFlags::TRUSTED);
3038 app_.getOPs().processTransaction(
3039 tx, trusted,
false, NetworkOPs::FailHard::no);
3043 JLOG(p_journal_.warn())
3044 <<
"Exception in " << __func__ <<
": " << ex.
what();
3045 app_.getHashRouter().setFlags(
3046 stx->getTransactionID(), HashRouterFlags::BAD);
3047 using namespace std::string_literals;
3048 charge(Resource::feeInvalidData,
"tx "s + ex.
what());
3054PeerImp::checkPropose(
3059 JLOG(p_journal_.trace())
3060 <<
"Checking " << (isTrusted ?
"trusted" :
"UNTRUSTED") <<
" proposal";
3062 XRPL_ASSERT(packet,
"ripple::PeerImp::checkPropose : non-null packet");
3067 JLOG(p_journal_.warn()) << desc;
3068 charge(Resource::feeInvalidSignature, desc);
3075 relay = app_.getOPs().processTrustedProposal(peerPos);
3077 relay = app_.config().RELAY_UNTRUSTED_PROPOSALS == 1 || cluster();
3085 auto haveMessage = app_.overlay().relay(
3087 if (!haveMessage.empty())
3088 overlay_.updateSlotAndSquelch(
3091 std::move(haveMessage),
3092 protocol::mtPROPOSE_LEDGER);
3097PeerImp::checkValidation(
3102 if (!val->isValid())
3104 std::string desc{
"Validation forwarded by peer is invalid"};
3105 JLOG(p_journal_.debug()) << desc;
3106 charge(Resource::feeInvalidSignature, desc);
3121 overlay_.relay(*packet, key, val->getSignerPublic());
3122 if (!haveMessage.empty())
3124 overlay_.updateSlotAndSquelch(
3126 val->getSignerPublic(),
3127 std::move(haveMessage),
3128 protocol::mtVALIDATION);
3134 JLOG(p_journal_.trace())
3135 <<
"Exception processing validation: " << ex.
what();
3136 using namespace std::string_literals;
3137 charge(Resource::feeMalformedRequest,
"validation "s + ex.
what());
3151 if (p->hasTxSet(rootHash) && p.get() != skip)
3153 auto score = p->getScore(true);
3154 if (!ret || (score > retScore))
3179 if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
3181 auto score = p->getScore(true);
3182 if (!ret || (score > retScore))
3194PeerImp::sendLedgerBase(
3196 protocol::TMLedgerData& ledgerData)
3198 JLOG(p_journal_.trace()) <<
"sendLedgerBase: Base data";
3201 addRaw(ledger->info(), s);
3204 auto const& stateMap{ledger->stateMap()};
3205 if (stateMap.getHash() != beast::zero)
3210 stateMap.serializeRoot(
root);
3211 ledgerData.add_nodes()->set_nodedata(
3212 root.getDataPtr(),
root.getLength());
3214 if (ledger->info().txHash != beast::zero)
3216 auto const& txMap{ledger->txMap()};
3217 if (txMap.getHash() != beast::zero)
3221 txMap.serializeRoot(
root);
3222 ledgerData.add_nodes()->set_nodedata(
3223 root.getDataPtr(),
root.getLength());
3236 JLOG(p_journal_.trace()) <<
"getLedger: Ledger";
3240 if (m->has_ledgerhash())
3243 uint256 const ledgerHash{m->ledgerhash()};
3244 ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash);
3247 JLOG(p_journal_.trace())
3248 <<
"getLedger: Don't have ledger with hash " << ledgerHash;
3250 if (m->has_querytype() && !m->has_requestcookie())
3256 m->has_ledgerseq() ? m->ledgerseq() : 0,
3259 m->set_requestcookie(
id());
3262 JLOG(p_journal_.debug())
3263 <<
"getLedger: Request relayed to peer";
3267 JLOG(p_journal_.trace())
3268 <<
"getLedger: Failed to find peer to relay request";
3272 else if (m->has_ledgerseq())
3275 if (m->ledgerseq() < app_.getLedgerMaster().getEarliestFetch())
3277 JLOG(p_journal_.debug())
3278 <<
"getLedger: Early ledger sequence request";
3282 ledger = app_.getLedgerMaster().getLedgerBySeq(m->ledgerseq());
3285 JLOG(p_journal_.debug())
3286 <<
"getLedger: Don't have ledger with sequence "
3291 else if (m->has_ltype() && m->ltype() == protocol::ltCLOSED)
3293 ledger = app_.getLedgerMaster().getClosedLedger();
3299 auto const ledgerSeq{ledger->info().seq};
3300 if (m->has_ledgerseq())
3302 if (ledgerSeq != m->ledgerseq())
3305 if (!m->has_requestcookie())
3307 Resource::feeMalformedRequest,
"get_ledger ledgerSeq");
3310 JLOG(p_journal_.warn())
3311 <<
"getLedger: Invalid ledger sequence " << ledgerSeq;
3314 else if (ledgerSeq < app_.getLedgerMaster().getEarliestFetch())
3317 JLOG(p_journal_.debug())
3318 <<
"getLedger: Early ledger sequence request " << ledgerSeq;
3323 JLOG(p_journal_.debug()) <<
"getLedger: Unable to find ledger";
3332 JLOG(p_journal_.trace()) <<
"getTxSet: TX set";
3334 uint256 const txSetHash{m->ledgerhash()};
3336 app_.getInboundTransactions().getSet(txSetHash,
false)};
3339 if (m->has_querytype() && !m->has_requestcookie())
3344 m->set_requestcookie(
id());
3347 JLOG(p_journal_.debug()) <<
"getTxSet: Request relayed";
3351 JLOG(p_journal_.debug())
3352 <<
"getTxSet: Failed to find relay peer";
3357 JLOG(p_journal_.debug()) <<
"getTxSet: Failed to find TX set";
3368 if (!m->has_requestcookie())
3370 Resource::feeModerateBurdenPeer,
"received a get ledger request");
3374 SHAMap const* map{
nullptr};
3375 protocol::TMLedgerData ledgerData;
3376 bool fatLeaves{
true};
3377 auto const itype{m->itype()};
3379 if (itype == protocol::liTS_CANDIDATE)
3381 if (sharedMap = getTxSet(m); !sharedMap)
3383 map = sharedMap.
get();
3386 ledgerData.set_ledgerseq(0);
3387 ledgerData.set_ledgerhash(m->ledgerhash());
3388 ledgerData.set_type(protocol::liTS_CANDIDATE);
3389 if (m->has_requestcookie())
3390 ledgerData.set_requestcookie(m->requestcookie());
3397 if (send_queue_.size() >= Tuning::dropSendQueue)
3399 JLOG(p_journal_.debug())
3400 <<
"processLedgerRequest: Large send queue";
3403 if (app_.getFeeTrack().isLoadedLocal() && !cluster())
3405 JLOG(p_journal_.debug()) <<
"processLedgerRequest: Too busy";
3409 if (ledger = getLedger(m); !ledger)
3413 auto const ledgerHash{ledger->info().hash};
3414 ledgerData.set_ledgerhash(ledgerHash.begin(), ledgerHash.size());
3415 ledgerData.set_ledgerseq(ledger->info().seq);
3416 ledgerData.set_type(itype);
3417 if (m->has_requestcookie())
3418 ledgerData.set_requestcookie(m->requestcookie());
3422 case protocol::liBASE:
3423 sendLedgerBase(ledger, ledgerData);
3426 case protocol::liTX_NODE:
3427 map = &ledger->txMap();
3428 JLOG(p_journal_.trace()) <<
"processLedgerRequest: TX map hash "
3429 << to_string(map->getHash());
3432 case protocol::liAS_NODE:
3433 map = &ledger->stateMap();
3434 JLOG(p_journal_.trace())
3435 <<
"processLedgerRequest: Account state map hash "
3436 << to_string(map->getHash());
3441 JLOG(p_journal_.error())
3442 <<
"processLedgerRequest: Invalid ledger info type";
3449 JLOG(p_journal_.warn()) <<
"processLedgerRequest: Unable to find map";
3454 if (m->nodeids_size() > 0)
3456 auto const queryDepth{
3457 m->has_querydepth() ? m->querydepth() : (isHighLatency() ? 2 : 1)};
3461 for (
int i = 0; i < m->nodeids_size() &&
3462 ledgerData.nodes_size() < Tuning::softMaxReplyNodes;
3468 data.reserve(Tuning::softMaxReplyNodes);
3472 if (map->getNodeFat(*shaMapNodeId, data, fatLeaves, queryDepth))
3474 JLOG(p_journal_.trace())
3475 <<
"processLedgerRequest: getNodeFat got "
3476 << data.size() <<
" nodes";
3478 for (
auto const& d : data)
3480 if (ledgerData.nodes_size() >=
3481 Tuning::hardMaxReplyNodes)
3483 protocol::TMLedgerNode* node{ledgerData.add_nodes()};
3484 node->set_nodeid(d.first.getRawString());
3485 node->set_nodedata(d.second.data(), d.second.size());
3490 JLOG(p_journal_.warn())
3491 <<
"processLedgerRequest: getNodeFat returns false";
3499 case protocol::liBASE:
3501 info =
"Ledger base";
3504 case protocol::liTX_NODE:
3508 case protocol::liAS_NODE:
3512 case protocol::liTS_CANDIDATE:
3513 info =
"TS candidate";
3521 if (!m->has_ledgerhash())
3522 info +=
", no hash specified";
3524 JLOG(p_journal_.warn())
3525 <<
"processLedgerRequest: getNodeFat with nodeId "
3526 << *shaMapNodeId <<
" and ledger info type " << info
3527 <<
" throws exception: " << e.
what();
3531 JLOG(p_journal_.info())
3532 <<
"processLedgerRequest: Got request for " << m->nodeids_size()
3533 <<
" nodes at depth " << queryDepth <<
", return "
3534 << ledgerData.nodes_size() <<
" nodes";
3537 if (ledgerData.nodes_size() == 0)
3544PeerImp::getScore(
bool haveItem)
const
3548 static int const spRandomMax = 9999;
3552 static int const spHaveItem = 10000;
3557 static int const spLatency = 30;
3560 static int const spNoLatency = 8000;
3565 score += spHaveItem;
3574 score -= latency->count() * spLatency;
3576 score -= spNoLatency;
3582PeerImp::isHighLatency()
const
3585 return latency_ >= peerHighLatency;
3591 using namespace std::chrono_literals;
3594 totalBytes_ += bytes;
3595 accumBytes_ += bytes;
3596 auto const timeElapsed = clock_type::now() - intervalStart_;
3597 auto const timeElapsedInSecs =
3598 std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
3600 if (timeElapsedInSecs >= 1s)
3602 auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
3603 rollingAvg_.push_back(avgBytes);
3605 auto const totalBytes =
3607 rollingAvgBytes_ = totalBytes / rollingAvg_.size();
3609 intervalStart_ = clock_type::now();
3615PeerImp::Metrics::average_bytes()
const
3618 return rollingAvgBytes_;
3622PeerImp::Metrics::total_bytes()
const
A version-independent IP address and port combination.
Address const & address() const
Returns the address portion of this endpoint.
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Endpoint at_port(Port port) const
Returns a new Endpoint with a different port.
static Endpoint from_string(std::string const &s)
std::string to_string() const
Returns a string representing the endpoint.
bool active(Severity level) const
Returns true if any message would be logged at this severity level.
Stream trace() const
Severity stream access functions.
virtual Config & config()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual TimeKeeper & timeKeeper()=0
virtual JobQueue & getJobQueue()=0
virtual NetworkOPs & getOPs()=0
virtual ValidatorList & validators()=0
virtual std::optional< PublicKey const > getValidationPublicKey() const =0
virtual LedgerMaster & getLedgerMaster()=0
virtual Cluster & cluster()=0
virtual HashRouter & getHashRouter()=0
void for_each(std::function< void(ClusterNode const &)> func) const
Invokes the callback once for every cluster node.
std::size_t size() const
The number of nodes in the cluster list.
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.
std::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
bool VP_REDUCE_RELAY_BASE_SQUELCH_ENABLE
bool TX_REDUCE_RELAY_METRICS
std::chrono::seconds MAX_DIVERGED_TIME
std::chrono::seconds MAX_UNKNOWN_TIME
bool shouldProcess(uint256 const &key, PeerShortID peer, HashRouterFlags &flags, std::chrono::seconds tx_interval)
bool addSuppressionPeer(uint256 const &key, PeerShortID peer)
std::unique_ptr< LoadEvent > makeLoadEvent(JobType t, std::string const &name)
Return a scoped LoadEvent.
int getJobCount(JobType t) const
Jobs waiting at this priority.
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
LedgerIndex getValidLedgerIndex()
std::chrono::seconds getValidatedLedgerAge()
void setClusterFee(std::uint32_t fee)
static std::size_t messageSize(::google::protobuf::Message const &message)
virtual bool isNeedNetworkLedger()=0
PeerFinder::Manager & peerFinder()
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...
void deletePeer(Peer::id_t id)
Called when the peer is deleted.
void incPeerDisconnect() override
Increment and retrieve counters for total peer disconnects, and disconnects we initiate for excessive...
void addTxMetrics(Args... args)
Add tx reduce-relay metrics.
void onPeerDeactivate(Peer::id_t id)
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
void reportOutboundTraffic(TrafficCount::category cat, int bytes)
void for_each(UnaryFunc &&f) const
Resource::Manager & resourceManager()
void reportInboundTraffic(TrafficCount::category cat, int bytes)
void onManifests(std::shared_ptr< protocol::TMManifests > const &m, std::shared_ptr< PeerImp > const &from)
Setup const & setup() const
std::shared_ptr< Message > getManifestsMessage()
void incPeerDisconnectCharges() override
void incJqTransOverflow() override
Increment and retrieve counter for transaction job queue overflows.
virtual void on_endpoints(std::shared_ptr< Slot > const &slot, Endpoints const &endpoints)=0
Called when mtENDPOINTS is received.
virtual Config config()=0
Returns the configuration for the manager.
virtual void on_closed(std::shared_ptr< Slot > const &slot)=0
Called when the slot is closed.
virtual void on_failure(std::shared_ptr< Slot > const &slot)=0
Called when an outbound connection is deemed to have failed.
This class manages established peer-to-peer connections, handles message exchange,...
std::queue< std::shared_ptr< Message > > send_queue_
std::unique_ptr< LoadEvent > load_event_
boost::beast::http::fields const & headers_
void onMessageEnd(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m)
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
clock_type::duration uptime() const
void removeTxQueue(uint256 const &hash) override
Remove transaction's hash from the transactions' hashes queue.
protocol::TMStatusChange last_status_
boost::circular_buffer< uint256 > recentTxSets_
std::unique_ptr< stream_type > stream_ptr_
void onMessage(std::shared_ptr< protocol::TMManifests > const &m)
Tracking
Whether the peer's view of the ledger converges or diverges from ours.
Compressed compressionEnabled_
uint256 closedLedgerHash_
std::string domain() const
std::optional< std::uint32_t > lastPingSeq_
std::string const & fingerprint() const override
beast::Journal const journal_
void tryAsyncShutdown()
Attempts to perform a graceful SSL shutdown if conditions are met.
beast::Journal const p_journal_
PeerImp(PeerImp const &)=delete
void shutdown()
Initiates the peer disconnection sequence.
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
bool hasTxSet(uint256 const &hash) const override
clock_type::time_point lastPingTime_
void onMessageUnknown(std::uint16_t type)
std::shared_ptr< PeerFinder::Slot > const slot_
std::shared_mutex nameMutex_
boost::circular_buffer< uint256 > recentLedgers_
std::optional< std::chrono::milliseconds > latency_
void handleTransaction(std::shared_ptr< protocol::TMTransaction > const &m, bool eraseTxQueue, bool batch)
Called from onMessage(TMTransaction(s)).
beast::IP::Endpoint const remote_address_
Json::Value json() override
PublicKey const publicKey_
void close()
Forcibly closes the underlying socket connection.
hash_set< uint256 > txQueue_
void onMessageBegin(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m, std::size_t size, std::size_t uncompressed_size, bool isCompressed)
bool txReduceRelayEnabled_
void fail(std::string const &name, error_code ec)
Handles a failure associated with a specific error code.
clock_type::time_point trackingTime_
void cancelTimer() noexcept
Cancels any pending wait on the peer activity timer.
ProtocolVersion protocol_
reduce_relay::Squelch< UptimeClock > squelch_
std::string getVersion() const
Return the version of rippled that the peer is running, if reported.
struct ripple::PeerImp::@22 metrics_
uint256 previousLedgerHash_
void charge(Resource::Charge const &fee, std::string const &context) override
Adjust this peer's load balance based on the type of load imposed.
void onTimer(error_code const &ec)
Handles the expiration of the peer activity timer.
void send(std::shared_ptr< Message > const &m) override
boost::system::error_code error_code
void onReadMessage(error_code ec, std::size_t bytes_transferred)
bool ledgerReplayEnabled_
boost::asio::basic_waitable_timer< std::chrono::steady_clock > waitable_timer
bool crawl() const
Returns true if this connection will publicly share its IP address.
void setTimer(std::chrono::seconds interval)
Sets and starts the peer timer.
void sendTxQueue() override
Send aggregated transactions' hashes.
bool txReduceRelayEnabled() const override
bool supportsFeature(ProtocolFeature f) const override
void onWriteMessage(error_code ec, std::size_t bytes_transferred)
http_request_type request_
void addTxQueue(uint256 const &hash) override
Add transaction's hash to the transactions' hashes queue.
static std::string makePrefix(std::string const &fingerprint)
bool cluster() const override
Returns true if this connection is a member of the cluster.
void onShutdown(error_code ec)
Handles the completion of the asynchronous SSL shutdown.
boost::asio::strand< boost::asio::executor > strand_
void cycleStatus() override
boost::beast::multi_buffer read_buffer_
Resource::Consumer usage_
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
std::atomic< Tracking > tracking_
Represents a peer connection in the overlay.
A peer's signed, proposed position for use in RCLConsensus.
bool checkSign() const
Verify the signing hash of the proposal.
PublicKey const & publicKey() const
Public key of peer that sent the proposal.
uint256 const & suppressionID() const
Unique id used by hash router to suppress duplicates.
An endpoint that consumes resources.
int balance()
Returns the credit balance representing consumption.
bool disconnect(beast::Journal const &j)
Returns true if the consumer should be disconnected.
Disposition charge(Charge const &fee, std::string const &context={})
Apply a load charge to the consumer.
virtual void importConsumers(std::string const &origin, Gossip const &gossip)=0
Import packaged consumer information.
A SHAMap is both a radix tree with a fan-out of 16 and a Merkle tree.
std::size_t size() const noexcept
void const * data() const noexcept
void const * getDataPtr() const
An immutable linear range of bytes.
time_point now() const override
Returns the current time, using the server's clock.
static category categorize(::google::protobuf::Message const &message, protocol::MessageType type, bool inbound)
Given a protocol message, determine which traffic category it belongs to.
static void sendValidatorList(Peer &peer, std::uint64_t peerSequence, PublicKey const &publisherKey, std::size_t maxSequence, std::uint32_t rawVersion, std::string const &rawManifest, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, HashRouter &hashRouter, beast::Journal j)
void for_each_available(std::function< void(std::string const &manifest, std::uint32_t version, std::map< std::size_t, ValidatorBlobInfo > const &blobInfos, PublicKey const &pubKey, std::size_t maxSequence, uint256 const &hash)> func) const
Invokes the callback once for every available publisher list's raw data members.
static constexpr std::size_t size()
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
T emplace_back(T... args)
@ objectValue
object value (collection of name/value pairs).
Charge const feeMalformedRequest
Schedule of fees charged for imposing load on the server.
Charge const feeInvalidData
Charge const feeUselessData
Charge const feeTrivialPeer
Charge const feeModerateBurdenPeer
std::size_t constexpr readBufferBytes
Size of buffer used to read from the socket.
@ targetSendQueue
How many messages we consider reasonable sustained on a send queue.
@ maxQueryDepth
The maximum number of levels to search.
@ sendqIntervals
How many timer intervals a sendq has to stay large before we disconnect.
@ sendQueueLogFreq
How often to log send queue size.
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
auto measureDurationAndLog(Func &&func, std::string const &actionDescription, std::chrono::duration< Rep, Period > maxDelay, beast::Journal const &journal)
static constexpr std::size_t MAX_TX_QUEUE_SIZE
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string protocolMessageName(int type)
Returns the name of a protocol message given its type.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
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.
constexpr ProtocolVersion make_protocol(std::uint16_t major, std::uint16_t minor)
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
static constexpr char FEATURE_COMPR[]
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
@ ValidatorListPropagation
@ ValidatorList2Propagation
std::string base64_decode(std::string_view data)
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::IP::Address public_ip, beast::IP::Address remote_ip, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
static bool stringIsUint256Sized(std::string const &pBuffStr)
static constexpr char FEATURE_LEDGER_REPLAY[]
std::pair< std::size_t, boost::system::error_code > invokeProtocolMessage(Buffers const &buffers, Handler &handler, std::size_t &hint)
Calls the handler for up to one protocol message in the passed buffers.
std::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
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.
std::string strHex(FwdIt begin, FwdIt end)
static std::shared_ptr< PeerImp > getPeerWithLedger(OverlayImpl &ov, uint256 const &ledgerHash, LedgerIndex ledger, PeerImp const *skip)
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)
Stopwatch & stopwatch()
Returns an instance of a wall clock.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
std::string getFingerprint(beast::IP::Endpoint const &address, std::optional< PublicKey > const &publicKey=std::nullopt, std::optional< std::string > const &id=std::nullopt)
static std::shared_ptr< PeerImp > getPeerWithTree(OverlayImpl &ov, uint256 const &rootHash, PeerImp const *skip)
bool peerFeatureEnabled(headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
static constexpr char FEATURE_TXRR[]
std::string to_string(base_uint< Bits, Tag > const &a)
std::optional< Rules > const & getCurrentTransactionRules()
Number root(Number f, unsigned d)
@ proposal
proposal for signing
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
static constexpr char FEATURE_VPRR[]
constexpr std::uint32_t tfInnerBatchTxn
T shared_from_this(T... args)
beast::IP::Address public_ip
std::optional< std::uint32_t > networkID
bool peerPrivate
true if we want our IP address kept private.
void update(Resource::Charge f, std::string const &add)
Describes a single consumer.
beast::IP::Endpoint address
Data format for exchanging consumption information across peers.
std::vector< Item > items