1#include <xrpld/overlay/detail/PeerImp.h>
3#include <xrpld/app/consensus/RCLCxPeerPos.h>
4#include <xrpld/app/consensus/RCLValidations.h>
5#include <xrpld/app/ledger/InboundLedgers.h>
6#include <xrpld/app/ledger/InboundTransactions.h>
7#include <xrpld/app/ledger/LedgerMaster.h>
8#include <xrpld/app/ledger/LedgerNodeHelpers.h>
9#include <xrpld/app/ledger/TransactionMaster.h>
10#include <xrpld/app/misc/Transaction.h>
11#include <xrpld/app/misc/ValidatorList.h>
12#include <xrpld/overlay/Cluster.h>
13#include <xrpld/overlay/ClusterNode.h>
14#include <xrpld/overlay/Peer.h>
15#include <xrpld/overlay/ReduceRelayCommon.h>
16#include <xrpld/overlay/detail/Handshake.h>
17#include <xrpld/overlay/detail/OverlayImpl.h>
18#include <xrpld/overlay/detail/ProtocolMessage.h>
19#include <xrpld/overlay/detail/ProtocolVersion.h>
20#include <xrpld/overlay/detail/TrafficCount.h>
21#include <xrpld/overlay/detail/Tuning.h>
23#include <xrpl/basics/Blob.h>
24#include <xrpl/basics/Log.h>
25#include <xrpl/basics/SHAMapHash.h>
26#include <xrpl/basics/Slice.h>
27#include <xrpl/basics/ToString.h>
28#include <xrpl/basics/UptimeClock.h>
29#include <xrpl/basics/base64.h>
30#include <xrpl/basics/base_uint.h>
31#include <xrpl/basics/chrono.h>
32#include <xrpl/basics/random.h>
33#include <xrpl/basics/safe_cast.h>
34#include <xrpl/basics/strHex.h>
35#include <xrpl/beast/utility/Journal.h>
36#include <xrpl/beast/utility/Zero.h>
37#include <xrpl/beast/utility/instrumentation.h>
38#include <xrpl/consensus/Validations.h>
39#include <xrpl/core/HashRouter.h>
40#include <xrpl/core/Job.h>
41#include <xrpl/core/PerfLog.h>
42#include <xrpl/json/json_forwards.h>
43#include <xrpl/json/json_value.h>
44#include <xrpl/ledger/Ledger.h>
45#include <xrpl/peerfinder/Slot.h>
46#include <xrpl/peerfinder/Types.h>
47#include <xrpl/protocol/KeyType.h>
48#include <xrpl/protocol/LedgerHeader.h>
49#include <xrpl/protocol/Protocol.h>
50#include <xrpl/protocol/PublicKey.h>
51#include <xrpl/protocol/SField.h>
52#include <xrpl/protocol/STTx.h>
53#include <xrpl/protocol/Serializer.h>
54#include <xrpl/protocol/TxFlags.h>
55#include <xrpl/protocol/digest.h>
56#include <xrpl/protocol/jss.h>
57#include <xrpl/protocol/tokens.h>
58#include <xrpl/resource/Charge.h>
59#include <xrpl/resource/Consumer.h>
60#include <xrpl/resource/Disposition.h>
61#include <xrpl/resource/Fees.h>
62#include <xrpl/resource/Gossip.h>
63#include <xrpl/server/LoadFeeTrack.h>
64#include <xrpl/server/Manifest.h>
65#include <xrpl/server/NetworkOPs.h>
66#include <xrpl/shamap/SHAMap.h>
67#include <xrpl/shamap/SHAMapNodeID.h>
68#include <xrpl/tx/apply.h>
70#include <boost/algorithm/string/predicate.hpp>
71#include <boost/asio/bind_executor.hpp>
72#include <boost/asio/buffer.hpp>
73#include <boost/asio/completion_condition.hpp>
74#include <boost/asio/dispatch.hpp>
75#include <boost/asio/error.hpp>
76#include <boost/asio/strand.hpp>
77#include <boost/asio/write.hpp>
78#include <boost/beast/core/multi_buffer.hpp>
79#include <boost/beast/core/ostream.hpp>
80#include <boost/system/system_error.hpp>
82#include <google/protobuf/message.h>
106using namespace std::chrono_literals;
114constexpr std::chrono::milliseconds kPeerHighLatency{300};
119constexpr std::chrono::seconds kPeerTimerInterval{60};
177 <<
" vp reduce-relay base squelch enabled "
184 bool const inCluster{
cluster()};
209 if (
uint256 ret; ret.parseHex(value))
221 if (
auto const iter = self->headers_.find(
"Closed-Ledger"); iter != self->headers_.end())
223 closed = parseLedgerHash(iter->value());
226 self->fail(
"Malformed handshake data (1)");
229 if (
auto const iter = self->headers_.find(
"Previous-Ledger"); iter != self->headers_.end())
231 previous = parseLedgerHash(iter->value());
234 self->fail(
"Malformed handshake data (2)");
237 if (previous && !closed)
238 self->fail(
"Malformed handshake data (3)");
243 self->closedLedgerHash_ = *closed;
245 self->previousLedgerHash_ = *previous;
254 self->doProtocolStart();
266 if (!self->socket_.is_open())
279 if (self->gracefulClose_)
281 if (self->detaching_)
283 if (!self->socket_.is_open())
286 auto validator = m->getValidatorKey();
287 if (validator && !self->squelch_.expireSquelch(*validator))
289 self->overlay_.reportOutboundTraffic(
291 static_cast<int>(m->getBuffer(self->compressionEnabled_).size()));
296 self->overlay_.reportOutboundTraffic(
298 static_cast<int>(m->getBuffer(self->compressionEnabled_).size()));
301 self->overlay_.reportOutboundTraffic(
303 static_cast<int>(m->getBuffer(self->compressionEnabled_).size()));
305 auto sendqSize = self->sendQueue_.size();
312 self->largeSendq_ = 0;
315 auto sink = self->journal_.debug();
319 sink << n <<
" sendq: " << sendqSize;
322 self->sendQueue_.push(m);
327 boost::asio::async_write(
329 boost::asio::buffer(self->sendQueue_.front()->getBuffer(self->compressionEnabled_)),
332 self->onWriteMessage(ec, bytesTransferred);
341 if (!self->txQueue_.empty())
343 protocol::TMHaveTransactions ht;
345 self->txQueue_, [&](
auto const& hash) { ht.add_hashes(hash.data(), hash.size()); });
346 JLOG(self->pJournal_.trace()) <<
"sendTxQueue " << self->txQueue_.size();
347 self->txQueue_.clear();
359 JLOG(self->pJournal_.warn()) <<
"addTxQueue exceeds the cap";
363 self->txQueue_.insert(hash);
364 JLOG(self->pJournal_.trace()) <<
"addTxQueue " << self->txQueue_.size();
372 auto removed = self->txQueue_.erase(hash);
373 JLOG(self->pJournal_.trace()) <<
"removeTxQueue " << removed;
382 self->usage_.disconnect(self->pJournal_))
390 bool expected =
false;
391 if (self->chargeDisconnectFired_.compare_exchange_strong(
392 expected,
true, std::memory_order_acq_rel))
394 self->overlay_.incPeerDisconnectCharges();
395 self->fail(
"charge: Resources");
406 auto const iter =
headers_.find(
"Crawl");
409 return boost::iequals(iter->value(),
"public");
435 ret[jss::inbound] =
true;
439 ret[jss::cluster] =
true;
451 if (
auto const nid =
headers_[
"Network-ID"]; !nid.empty())
454 ret[jss::load] =
usage_.balance();
473 if ((minSeq != 0) || (maxSeq != 0))
479 ret[jss::track] =
"diverged";
483 ret[jss::track] =
"unknown";
492 protocol::TMStatusChange lastStatus;
500 ret[jss::ledger] =
to_string(closedLedgerHash);
502 if (lastStatus.has_newstatus())
504 switch (lastStatus.newstatus())
506 case protocol::nsCONNECTING:
507 ret[jss::status] =
"connecting";
510 case protocol::nsCONNECTED:
511 ret[jss::status] =
"connected";
514 case protocol::nsMONITORING:
515 ret[jss::status] =
"monitoring";
518 case protocol::nsVALIDATING:
519 ret[jss::status] =
"validating";
522 case protocol::nsSHUTTING:
523 ret[jss::status] =
"shutting";
527 JLOG(
pJournal_.warn()) <<
"Unknown status: " << lastStatus.newstatus();
607 XRPL_ASSERT(
strand_.running_in_this_thread(),
"xrpl::PeerImp::close : strand in this thread");
628 JLOG(self->journal_.warn()) << n <<
" failed: " << reason;
637 XRPL_ASSERT(
strand_.running_in_this_thread(),
"xrpl::PeerImp::fail : strand in this thread");
650 strand_.running_in_this_thread(),
"xrpl::PeerImp::gracefulClose : strand in this thread");
651 XRPL_ASSERT(
socket_.is_open(),
"xrpl::PeerImp::gracefulClose : socket is open");
652 XRPL_ASSERT(!
gracefulClose_,
"xrpl::PeerImp::gracefulClose : socket is not closing");
657 stream_.async_shutdown(bind_executor(
666 timer_.expires_after(kPeerTimerInterval);
668 catch (boost::system::system_error
const& e)
670 JLOG(
journal_.error()) <<
"setTimer: " << e.code();
673 timer_.async_wait(bind_executor(
685 catch (boost::system::system_error
const&)
709 if (ec == boost::asio::error::operation_aborted)
713 JLOG(
journal_.error()) <<
"onTimer: " << ec.message();
720 fail(
"Large send queue");
726 clock_type::duration duration;
745 fail(
"Ping Timeout");
752 protocol::TMPing message;
753 message.set_type(protocol::TMPing::ptPING);
773 bool const shouldLog =
774 (ec != boost::asio::error::eof && ec != boost::asio::error::operation_aborted &&
775 !ec.message().contains(
"application data after close notify"));
779 JLOG(
journal_.debug()) <<
"onShutdown: " << ec.message();
790 XRPL_ASSERT(
readBuffer_.size() == 0,
"xrpl::PeerImp::doAccept : empty read buffer");
798 fail(
"makeSharedValue: Unexpected failure");
810 JLOG(
journal_.info()) <<
"Cluster name: " << *member;
822 !
overlay_.peerFinder().config().peerPrivate,
832 boost::asio::async_write(
835 boost::asio::transfer_all(),
844 if (ec == boost::asio::error::operation_aborted)
847 fail(
"onWriteResponse", ec);
851 if (writeBuffer->size() == bytesTransferred)
856 fail(
"Failed to write header");
886 app_.getValidators().forEachAvailable(
901 app_.getHashRouter(),
905 app_.getHashRouter().addSuppressionPeer(hash,
id_);
909 if (
auto m =
overlay_.getManifestsMessage())
924 if (ec == boost::asio::error::operation_aborted)
927 if (ec == boost::asio::error::eof)
934 fail(
"onReadMessage", ec);
940 stream <<
"onReadMessage: "
941 << (bytesTransferred > 0 ?
to_string(bytesTransferred) +
" bytes" :
"");
944 metrics_.recv.addMessage(bytesTransferred);
954 using namespace std::chrono_literals;
957 "invokeProtocolMessage",
963 fail(
"onReadMessage", ec);
973 if (bytesConsumed == 0)
984 self->onReadMessage(ec, bytesTransferred);
996 if (ec == boost::asio::error::operation_aborted)
999 fail(
"onWriteMessage", ec);
1002 if (
auto stream =
journal_.trace())
1004 stream <<
"onWriteMessage: "
1005 << (bytesTransferred > 0 ?
to_string(bytesTransferred) +
" bytes" :
"");
1008 metrics_.sent.addMessage(bytesTransferred);
1010 XRPL_ASSERT(!
sendQueue_.empty(),
"xrpl::PeerImp::onWriteMessage : non-empty send buffer");
1015 boost::asio::async_write(
1021 self->onWriteMessage(ec, bytesTransferred);
1028 stream_.async_shutdown(bind_executor(
1058 auto const category =
1065 overlay_.reportInboundTraffic(category,
static_cast<int>(size));
1068 if ((type == MessageType::mtTRANSACTION || type == MessageType::mtHAVE_TRANSACTIONS ||
1069 type == MessageType::mtTRANSACTIONS ||
1082 JLOG(
journal_.trace()) <<
"onMessageBegin: " << type <<
" " << size <<
" " << uncompressedSize
1083 <<
" " << isCompressed;
1096 auto const s = m->list_size();
1118 if (m->type() == protocol::TMPing::ptPING)
1122 protocol::TMPing pong;
1123 pong.set_type(protocol::TMPing::ptPONG);
1125 pong.set_seq(m->seq());
1130 if (m->type() == protocol::TMPing::ptPONG && m->has_seq())
1169 for (
int i = 0; i < m->clusternodes().size(); ++i)
1171 protocol::TMClusterNode
const& node = m->clusternodes(i);
1174 if (node.has_nodename())
1175 name = node.nodename();
1185 app_.getCluster().update(*publicKey,
name, node.nodeload(), reportTime);
1189 int const loadSources = m->loadsources().size();
1190 if (loadSources != 0)
1193 gossip.
items.reserve(loadSources);
1194 for (
int i = 0; i < m->loadsources().size(); ++i)
1196 protocol::TMLoadSource
const& node = m->loadsources(i);
1201 gossip.
items.push_back(item);
1203 overlay_.resourceManager().importConsumers(
name(), gossip);
1207 auto const thresh =
app_.getTimeKeeper().now() - 90s;
1213 app_.getCluster().forEach([&fees, thresh](
ClusterNode const& status) {
1214 if (status.getReportTime() >= thresh)
1220 auto const index = fees.
size() / 2;
1222 clusterFee = fees[index];
1225 app_.getFeeTrack().setClusterFee(clusterFee);
1238 if (m->endpoints_v2().size() >= 1024)
1245 endpoints.
reserve(m->endpoints_v2().size());
1248 for (
auto const& tm : m->endpoints_v2())
1255 <<
"failed to parse incoming endpoint: {" << tm.endpoint() <<
"}";
1281 if (!endpoints.
empty())
1297 XRPL_ASSERT(eraseTxQueue != batch, (
"xrpl::PeerImp::handleTransaction : valid inputs"));
1301 if (
app_.getOPs().isNeedNetworkLedger())
1305 JLOG(
pJournal_.debug()) <<
"Ignoring incoming transaction: Need network ledger";
1314 uint256 const txID = stx->getTransactionID();
1336 JLOG(
pJournal_.warn()) <<
"Ignoring Network relayed Tx containing "
1337 "tfInnerBatchTxn (handleTransaction).";
1346 if (!
app_.getHashRouter().shouldProcess(txID,
id_, flags, kTxInterval))
1352 JLOG(
pJournal_.debug()) <<
"Ignoring known bad tx " << txID;
1368 JLOG(
pJournal_.debug()) <<
"Got tx " << txID;
1370 bool checkSignature =
true;
1373 if (!m->has_deferred() || !m->deferred())
1382 if (!
app_.getValidationPublicKey())
1386 checkSignature =
false;
1390 if (
app_.getLedgerMaster().getValidatedLedgerAge() > 4min)
1392 JLOG(
pJournal_.trace()) <<
"No new transactions until synchronized";
1397 JLOG(
pJournal_.info()) <<
"Transaction queue is full";
1401 app_.getJobQueue().addJob(
1409 if (
auto peer = weak.lock())
1410 peer->checkTransaction(flags, checkSignature, stx, batch);
1416 JLOG(
pJournal_.warn()) <<
"Transaction invalid: " <<
strHex(m->rawtransaction())
1417 <<
". Exception: " << ex.
what();
1426 JLOG(
pJournal_.warn()) <<
"TMGetLedger: " << msg;
1428 auto const itype{m->itype()};
1431 if (itype < protocol::liBASE || itype > protocol::liTS_CANDIDATE)
1433 badData(
"Invalid ledger info type");
1440 return std::nullopt;
1443 if (itype == protocol::liTS_CANDIDATE)
1445 if (!m->has_ledgerhash())
1447 badData(
"Invalid TX candidate set, missing TX set hash");
1452 !m->has_ledgerhash() && !m->has_ledgerseq() && (!ltype || *ltype != protocol::ltCLOSED))
1454 badData(
"Invalid request");
1459 if (ltype && (*ltype < protocol::ltACCEPTED || *ltype > protocol::ltCLOSED))
1461 badData(
"Invalid ledger type");
1468 badData(
"Invalid ledger hash");
1473 if (m->has_ledgerseq())
1475 auto const ledgerSeq{m->ledgerseq()};
1478 using namespace std::chrono_literals;
1479 if (
app_.getLedgerMaster().getValidatedLedgerAge() <= 10s &&
1480 ledgerSeq >
app_.getLedgerMaster().getValidLedgerIndex() + 10)
1489 if (itype != protocol::liBASE && m->nodeids_size() <= 0)
1491 badData(
"Invalid ledger node IDs");
1496 if (m->has_querytype() && m->querytype() != protocol::qtINDIRECT)
1498 badData(
"Invalid query type");
1503 if (m->has_querydepth())
1507 badData(
"Invalid query depth");
1514 app_.getJobQueue().addJob(
JtLedgerReq,
"RcvGetLedger", [weak, m, itype]() {
1515 auto peer = weak.
lock();
1520 bool tooManyNodeIds =
false;
1521 if (itype != protocol::liBASE)
1524 for (
auto const& nodeId : m->nodeids())
1531 tooManyNodeIds =
true;
1553 m->mutable_nodeids()->DeleteSubrange(
1554 static_cast<int>(nodeIDs.
size()),
1555 m->nodeids_size() -
static_cast<int>(nodeIDs.
size()));
1557 if (!m->has_requestcookie())
1562 peer->processLedgerRequest(m, std::move(nodeIDs));
1569 JLOG(
pJournal_.trace()) <<
"onMessage, TMProofPathRequest";
1579 if (
auto peer = weak.
lock())
1581 auto reply = peer->ledgerReplayMsgHandler_.processProofPathRequest(m);
1582 if (reply.has_error())
1584 if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1626 JLOG(
pJournal_.trace()) <<
"onMessage, TMReplayDeltaRequest";
1636 if (
auto peer = weak.
lock())
1638 auto reply = peer->ledgerReplayMsgHandler_.processReplayDeltaRequest(m);
1639 if (reply.has_error())
1641 if (reply.error() == protocol::TMReplyError::reBAD_REQUEST)
1685 JLOG(
pJournal_.warn()) <<
"TMLedgerData: " << msg;
1691 badData(
"Invalid ledger hash");
1697 auto const ledgerSeq{m->ledgerseq()};
1698 if (m->type() == protocol::liTS_CANDIDATE)
1709 using namespace std::chrono_literals;
1710 if (
app_.getLedgerMaster().getValidatedLedgerAge() <= 10s &&
1711 ledgerSeq >
app_.getLedgerMaster().getValidLedgerIndex() + 10)
1720 if (m->type() < protocol::liBASE || m->type() > protocol::liTS_CANDIDATE)
1722 badData(
"Invalid ledger info type");
1727 if (m->has_error() &&
1728 (m->error() < protocol::reNO_LEDGER || m->error() > protocol::reBAD_REQUEST))
1730 badData(
"Invalid reply error");
1737 badData(
"Invalid Ledger/TXset nodes " +
std::to_string(m->nodes_size()));
1742 if (m->has_requestcookie())
1744 if (
auto peer =
overlay_.findPeerByShortID(m->requestcookie()))
1746 m->clear_requestcookie();
1753 auto const peerSupportsNodeDepth =
1756 MessageType messageType = MessageType::Unknown;
1757 for (
int i = 0; i < m->nodes_size(); ++i)
1759 auto* ledgerNode = m->mutable_nodes(i);
1763 if (ledgerNode->nodedata().empty())
1766 "Received node with empty data while relaying ledger data for " +
1772 MessageType msgType = MessageType::Unknown;
1773 if (m->type() == protocol::liBASE)
1775 if (ledgerNode->has_nodeid() || ledgerNode->has_id() || ledgerNode->has_depth())
1778 "Received liBASE message with node reference while relaying ledger "
1784 msgType = MessageType::Base;
1788 msgType = ledgerNode->has_nodeid() ? MessageType::Legacy : MessageType::Depth;
1790 if (messageType != MessageType::Unknown && messageType != msgType)
1793 "Received mixed mode message while relaying ledger data for " +
1798 messageType = msgType;
1800 if (peerSupportsNodeDepth || msgType != MessageType::Depth)
1804 !peerSupportsNodeDepth,
1805 "xrpl::PeerImp : relaying depth-format ledger data to pre-2.3 peer");
1806 switch (ledgerNode->reference_case())
1808 case protocol::TMLedgerNode::kId: {
1811 REACHABLE(
"xrpl::PeerImp : relay downgrade id to nodeid");
1812 ledgerNode->set_nodeid(ledgerNode->id());
1813 ledgerNode->clear_id();
1816 case protocol::TMLedgerNode::kDepth: {
1818 auto treeNode =
getTreeNode(ledgerNode->nodedata());
1822 "Unable to get tree node while relaying ledger data for " +
1832 "Unable to get node ID while relaying ledger data for " +
1838 REACHABLE(
"xrpl::PeerImp : relay downgrade depth to nodeid");
1839 ledgerNode->set_nodeid(nodeID->getRawString());
1840 ledgerNode->clear_depth();
1844 SOMETIMES(
true,
"xrpl::PeerImp : relay node has empty reference");
1846 "Empty node reference while relaying ledger data for " +
1858 JLOG(
pJournal_.info()) <<
"Unable to route TX/ledger data reply";
1866 if (m->type() == protocol::liTS_CANDIDATE)
1869 app_.getJobQueue().addJob(
JtTxnData,
"RcvPeerData", [weak, ledgerHash, m]() {
1870 if (
auto peer = weak.
lock())
1872 peer->app_.getInboundTransactions().gotData(ledgerHash, peer, m);
1885 protocol::TMProposeSet
const&
set = *m;
1894 JLOG(
pJournal_.warn()) <<
"Proposal: malformed";
1901 JLOG(
pJournal_.warn()) <<
"Proposal: malformed";
1910 auto const isTrusted =
app_.getValidators().trusted(publicKey);
1921 if (
app_.config().relayUntrustedProposals == -1)
1931 proposeHash, prevLedger,
set.proposeseq(), closeTime, publicKey.
slice(), sig);
1933 if (
auto [added, relayed] =
app_.getHashRouter().addSuppressionPeerWithStatus(suppression,
id_);
1939 overlay_.updateSlotAndSquelch(suppression, publicKey,
id_, protocol::mtPROPOSE_LEDGER);
1945 JLOG(
pJournal_.trace()) <<
"Proposal: duplicate";
1954 JLOG(
pJournal_.debug()) <<
"Proposal: Dropping untrusted (peer divergence)";
1958 if (!
cluster() &&
app_.getFeeTrack().isLoadedLocal())
1960 JLOG(
pJournal_.debug()) <<
"Proposal: Dropping untrusted (load)";
1965 JLOG(
pJournal_.trace()) <<
"Proposal: " << (isTrusted ?
"trusted" :
"untrusted");
1976 app_.getTimeKeeper().closeTime(),
1977 calcNodeID(
app_.getValidatorManifests().getMasterKey(publicKey))});
1980 app_.getJobQueue().addJob(
1982 if (
auto peer = weak.lock())
1983 peer->checkPropose(isTrusted, m, proposal);
1990 JLOG(
pJournal_.trace()) <<
"Status: Change";
1992 if (!m->has_networktime())
1993 m->set_networktime(
app_.getTimeKeeper().now().time_since_epoch().count());
1997 if (!
lastStatus_.has_newstatus() || m->has_newstatus())
2004 protocol::NodeStatus
const status =
lastStatus_.newstatus();
2006 m->set_newstatus(status);
2010 if (m->newevent() == protocol::neLOST_SYNC)
2012 bool outOfSync{
false};
2026 JLOG(
pJournal_.debug()) <<
"Status: Out of sync";
2039 if (peerChangedLedgers)
2060 if (peerChangedLedgers)
2062 JLOG(
pJournal_.debug()) <<
"LCL is " << closedLedgerHash;
2066 JLOG(
pJournal_.debug()) <<
"Status: No ledger";
2070 if (m->has_firstseq() && m->has_lastseq())
2081 if (m->has_ledgerseq() &&
app_.getLedgerMaster().getValidatedLedgerAge() < 2min)
2089 if (m->has_newstatus())
2091 switch (m->newstatus())
2093 case protocol::nsCONNECTING:
2094 j[jss::status] =
"CONNECTING";
2096 case protocol::nsCONNECTED:
2097 j[jss::status] =
"CONNECTED";
2099 case protocol::nsMONITORING:
2100 j[jss::status] =
"MONITORING";
2102 case protocol::nsVALIDATING:
2103 j[jss::status] =
"VALIDATING";
2105 case protocol::nsSHUTTING:
2106 j[jss::status] =
"SHUTTING";
2111 if (m->has_newevent())
2113 switch (m->newevent())
2115 case protocol::neCLOSING_LEDGER:
2116 j[jss::action] =
"CLOSING_LEDGER";
2118 case protocol::neACCEPTED_LEDGER:
2119 j[jss::action] =
"ACCEPTED_LEDGER";
2121 case protocol::neSWITCHED_LEDGER:
2122 j[jss::action] =
"SWITCHED_LEDGER";
2124 case protocol::neLOST_SYNC:
2125 j[jss::action] =
"LOST_SYNC";
2130 if (m->has_ledgerseq())
2132 j[jss::ledger_index] = m->ledgerseq();
2135 if (m->has_ledgerhash())
2142 j[jss::ledger_hash] =
to_string(closedLedgerHash);
2145 if (m->has_networktime())
2150 if (m->has_firstseq() && m->has_lastseq())
2152 j[jss::ledger_index_min] =
json::UInt(m->firstseq());
2153 j[jss::ledger_index_max] =
json::UInt(m->lastseq());
2211 if (m->status() == protocol::tsHAVE)
2236 JLOG(
pJournal_.warn()) <<
"Ignored malformed " << messageType;
2242 auto const hash =
sha512Half(manifest, blobs, version);
2244 JLOG(
pJournal_.debug()) <<
"Received " << messageType;
2246 if (!
app_.getHashRouter().addSuppressionPeer(hash,
id_))
2248 JLOG(
pJournal_.debug()) << messageType <<
": received duplicate " << messageType;
2256 auto const applyResult =
app_.getValidators().applyListsAndBroadcast(
2263 app_.getHashRouter(),
2266 JLOG(
pJournal_.debug()) <<
"Processed " << messageType <<
" version " << version <<
" from "
2267 << (applyResult.publisherKey ?
strHex(*applyResult.publisherKey)
2268 :
"unknown or invalid publisher")
2269 <<
" with best result " <<
to_string(applyResult.bestDisposition());
2272 switch (applyResult.bestDisposition())
2283 applyResult.publisherKey,
2284 "xrpl::PeerImp::onValidatorListMessage : publisher key is "
2287 auto const& pubKey = *applyResult.publisherKey;
2293 iter->second < applyResult.sequence,
2294 "xrpl::PeerImp::onValidatorListMessage : lower sequence");
2307 applyResult.sequence && applyResult.publisherKey,
2308 "xrpl::PeerImp::onValidatorListMessage : nonzero sequence "
2309 "and set publisher key");
2312 "xrpl::PeerImp::onValidatorListMessage : maximum sequence");
2325 "xrpl::PeerImp::onValidatorListMessage : invalid best list "
2331 switch (applyResult.worstDisposition())
2368 "xrpl::PeerImp::onValidatorListMessage : invalid worst list "
2374 for (
auto const& [disp, count] : applyResult.dispositions)
2380 JLOG(
pJournal_.debug()) <<
"Applied " << count <<
" new " << messageType;
2384 JLOG(
pJournal_.debug()) <<
"Applied " << count <<
" expired " << messageType;
2388 JLOG(
pJournal_.debug()) <<
"Processed " << count <<
" future " << messageType;
2392 <<
"Ignored " << count <<
" " << messageType <<
"(s) with current sequence";
2396 <<
"Ignored " << count <<
" " << messageType <<
"(s) with future sequence";
2399 JLOG(
pJournal_.warn()) <<
"Ignored " << count <<
"stale " << messageType;
2402 JLOG(
pJournal_.warn()) <<
"Ignored " << count <<
" untrusted " << messageType;
2406 <<
"Ignored " << count <<
"unsupported version " << messageType;
2409 JLOG(
pJournal_.warn()) <<
"Ignored " << count <<
"invalid " << messageType;
2414 "xrpl::PeerImp::onValidatorListMessage : invalid list "
2426 if (m->version() < 2)
2429 <<
"ValidatorListCollection: received invalid validator list "
2440 JLOG(
pJournal_.warn()) <<
"ValidatorListCollection: Exception, " << e.
what();
2441 using namespace std::string_literals;
2449 if (m->validation().size() < 50)
2451 JLOG(
pJournal_.warn()) <<
"Validation: Too small";
2458 auto const closeTime =
app_.getTimeKeeper().closeTime();
2468 return calcNodeID(
app_.getValidatorManifests().getMasterKey(pk));
2471 .checkSignature =
false, .requireCanonicalOrder =
true});
2475 JLOG(
pJournal_.warn()) <<
"Validation: Exception, " << e.
what();
2479 val->setSeen(closeTime);
2483 app_.getValidations().parms(),
2484 app_.getTimeKeeper().closeTime(),
2486 val->getSeenTime()))
2488 JLOG(
pJournal_.trace()) <<
"Validation: Not current";
2496 auto const isTrusted =
app_.getValidators().trusted(val->getSignerPublic());
2507 if (
app_.config().relayUntrustedValidations == -1)
2513 auto [added, relayed] =
app_.getHashRouter().addSuppressionPeerWithStatus(key,
id_);
2523 key, val->getSignerPublic(),
id_, protocol::mtVALIDATION);
2530 JLOG(
pJournal_.trace()) <<
"Validation: duplicate";
2536 JLOG(
pJournal_.debug()) <<
"Dropping untrusted validation from diverged peer";
2538 else if (isTrusted || !
app_.getFeeTrack().isLoadedLocal())
2543 app_.getJobQueue().addJob(
2545 if (
auto peer = weak.
lock())
2546 peer->checkValidation(val, key, m);
2551 JLOG(
pJournal_.debug()) <<
"Dropping untrusted validation for load";
2556 JLOG(
pJournal_.warn()) <<
"Exception processing validation: " << e.
what();
2557 using namespace std::string_literals;
2565 protocol::TMGetObjectByHash
const& packet = *m;
2567 JLOG(
pJournal_.trace()) <<
"received TMGetObjectByHash " << packet.type() <<
" "
2568 << packet.objects_size();
2575 JLOG(
pJournal_.debug()) <<
"GetObject: Large send queue";
2579 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2585 if (packet.type() == protocol::TMGetObjectByHash::otTRANSACTIONS)
2589 JLOG(
pJournal_.error()) <<
"TMGetObjectByHash: tx reduce-relay is disabled";
2596 if (
auto peer = weak.
lock())
2597 peer->doTransactions(m);
2602 if (packet.has_ledgerhash())
2606 JLOG(
pJournal_.debug()) <<
"GetObj: malformed ledgerhash from peer " <<
id_;
2617 <<
"GetObj: oversized request from peer " <<
id_ <<
" (" << packet.objects_size()
2627 bool const queued =
app_.getJobQueue().addJob(
JtLedgerReq,
"RcvGetObjByHash", [weak, m]() {
2628 auto peer = weak.
lock();
2633 peer->processGetObjectByHash(m);
2640 JLOG(peer->pJournal_.warn()) <<
"GetObj: handler threw: " << e.
what();
2648 JLOG(
pJournal_.warn()) <<
"GetObj: job queue refused request from peer " <<
id_;
2665 bool progress =
false;
2667 for (
int i = 0; i < packet.objects_size(); ++i)
2669 protocol::TMIndexedObject
const& obj = packet.objects(i);
2673 if (obj.has_ledgerseq())
2675 if (obj.ledgerseq() != pLSeq)
2677 if (pLDo && (pLSeq != 0))
2679 JLOG(
pJournal_.debug()) <<
"GetObj: Full fetch pack for " << pLSeq;
2681 pLSeq = obj.ledgerseq();
2682 pLDo = !
app_.getLedgerMaster().haveLedger(pLSeq);
2686 JLOG(
pJournal_.debug()) <<
"GetObj: Late fetch pack for " << pLSeq;
2699 app_.getLedgerMaster().addFetchPack(
2705 if (pLDo && (pLSeq != 0))
2707 JLOG(
pJournal_.debug()) <<
"GetObj: Partial fetch pack for " << pLSeq;
2709 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2710 app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2717 protocol::TMGetObjectByHash
const& packet = *m;
2719 protocol::TMGetObjectByHash reply;
2720 reply.set_query(
false);
2721 reply.set_type(packet.type());
2723 if (packet.has_ledgerhash())
2725 reply.set_ledgerhash(packet.ledgerhash());
2736 int const requested = packet.objects_size();
2739 for (
int i = 0; i < iterLimit; ++i)
2741 auto const& obj = packet.objects(i);
2748 std::uint32_t const seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2749 auto const nodeObject =
app_.getNodeStore().fetchNodeObject(hash, seq);
2753 protocol::TMIndexedObject& newObj = *reply.add_objects();
2754 newObj.set_hash(hash.
begin(), hash.
size());
2755 auto const& data = nodeObject->getData();
2756 newObj.set_data(data.data(), data.size());
2757 if (obj.has_nodeid())
2758 newObj.set_index(obj.nodeid());
2759 if (obj.has_ledgerseq())
2760 newObj.set_ledgerseq(obj.ledgerseq());
2771 "processed get object by hash request");
2773 JLOG(
pJournal_.trace()) <<
"GetObj: " << reply.objects_size() <<
" of " << requested;
2782 JLOG(
pJournal_.error()) <<
"TMHaveTransactions: tx reduce-relay is disabled";
2789 if (
auto peer = weak.
lock())
2790 peer->handleHaveTransactions(m);
2797 protocol::TMGetObjectByHash tmBH;
2798 tmBH.set_type(protocol::TMGetObjectByHash_ObjectType_otTRANSACTIONS);
2799 tmBH.set_query(
true);
2801 JLOG(
pJournal_.trace()) <<
"received TMHaveTransactions " << m->hashes_size();
2807 JLOG(
pJournal_.error()) <<
"TMHaveTransactions with invalid hash size";
2814 auto txn =
app_.getMasterTransaction().fetchFromCache(hash);
2816 JLOG(
pJournal_.trace()) <<
"checking transaction " << (bool)txn;
2820 JLOG(
pJournal_.debug()) <<
"adding transaction to request";
2822 auto obj = tmBH.add_objects();
2823 obj->set_hash(hash.
data(), hash.
size());
2834 JLOG(
pJournal_.trace()) <<
"transaction request object is " << tmBH.objects_size();
2836 if (tmBH.objects_size() > 0)
2845 JLOG(
pJournal_.error()) <<
"TMTransactions: tx reduce-relay is disabled";
2850 JLOG(
pJournal_.trace()) <<
"received TMTransactions " << m->transactions_size();
2852 overlay_.addTxMetrics(m->transactions_size());
2858 m->mutable_transactions(i), [](protocol::TMTransaction*) {}),
2868 if (!m->has_validatorpubkey())
2873 auto validator = m->validatorpubkey();
2883 if (key == self->app_.getValidationPublicKey())
2885 JLOG(self->pJournal_.debug())
2886 <<
"onMessage: TMSquelch discarding validator's squelch " << slice;
2890 std::uint32_t const duration = m->has_squelchduration() ? m->squelchduration() : 0;
2893 self->squelch_.removeSquelch(key);
2900 JLOG(self->pJournal_.debug())
2901 <<
"onMessage: TMSquelch " << slice <<
" " << self->id() <<
" " << duration;
2912 (void)lockedRecentLock;
2926 if (
app_.getFeeTrack().isLoadedLocal() ||
2927 (
app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2928 (
app_.getJobQueue().getJobCount(
JtPack) > 10))
2930 JLOG(
pJournal_.info()) <<
"Too busy to make fetch pack";
2936 JLOG(
pJournal_.warn()) <<
"FetchPack hash size malformed";
2947 auto const pap = &
app_;
2948 app_.getJobQueue().addJob(
JtPack,
"MakeFetchPack", [pap, weak, packet, hash, elapsed]() {
2949 pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
2956 protocol::TMTransactions reply;
2958 JLOG(
pJournal_.trace()) <<
"received TMGetObjectByHash requesting tx "
2959 << packet->objects_size();
2963 JLOG(
pJournal_.error()) <<
"doTransactions, invalid number of hashes";
2970 auto const& obj = packet->objects(i);
2980 auto txn =
app_.getMasterTransaction().fetchFromCache(hash);
2985 <<
"doTransactions, transaction not found " <<
Slice(hash.
data(), hash.
size());
2991 auto tx = reply.add_transactions();
2992 auto sttx = txn->getSTransaction();
2994 tx->set_rawtransaction(s.
data(), s.
size());
2997 tx->set_receivetimestamp(
app_.getTimeKeeper().now().time_since_epoch().count());
2998 tx->set_deferred(txn->getSubmitResult().queued);
3001 if (reply.transactions_size() > 0)
3008 bool checkSignature,
3035 JLOG(
pJournal_.warn()) <<
"Ignoring Network relayed Tx containing "
3036 "tfInnerBatchTxn (checkSignature).";
3043 if (stx->isFieldPresent(sfLastLedgerSequence) &&
3044 (stx->getFieldU32(sfLastLedgerSequence) <
app_.getLedgerMaster().getValidLedgerIndex()))
3046 JLOG(
pJournal_.info()) <<
"Marking transaction " << stx->getTransactionID()
3047 <<
"as BAD because it's expired";
3061 "xrpl::PeerImp::checkTransaction Transaction created "
3065 JLOG(
pJournal_.debug()) <<
"Processing " << (batch ?
"batch" :
"unsolicited")
3066 <<
" pseudo-transaction tx " << tx->getID();
3068 app_.getMasterTransaction().canonicalize(&tx);
3070 auto const toSkip =
app_.getHashRouter().shouldRelay(tx->getID());
3074 <<
"Passing skipped pseudo pseudo-transaction tx " << tx->getID();
3075 app_.getOverlay().relay(tx->getID(), {}, *toSkip);
3079 JLOG(
pJournal_.debug()) <<
"Charging for pseudo-transaction tx " << tx->getID();
3091 app_.getHashRouter(), *stx,
app_.getLedgerMaster().getValidatedRules());
3094 if (!validReason.empty())
3096 JLOG(
pJournal_.debug()) <<
"Exception checking transaction: " << validReason;
3116 if (!reason.
empty())
3118 JLOG(
pJournal_.debug()) <<
"Exception checking transaction: " << reason;
3130 JLOG(
pJournal_.warn()) <<
"Exception in " << __func__ <<
": " << ex.
what();
3132 using namespace std::string_literals;
3144 JLOG(
pJournal_.trace()) <<
"Checking " << (isTrusted ?
"trusted" :
"UNTRUSTED") <<
" proposal";
3146 XRPL_ASSERT(packet,
"xrpl::PeerImp::checkPropose : non-null packet");
3150 std::string const desc{
"Proposal fails sig check"};
3160 relay =
app_.getOPs().processTrustedProposal(peerPos);
3164 relay =
app_.config().relayUntrustedProposals == 1 ||
cluster();
3175 if (!haveMessage.empty())
3180 std::move(haveMessage),
3181 protocol::mtPROPOSE_LEDGER);
3192 if (!val->isValid())
3194 std::string const desc{
"Validation forwarded by peer is invalid"};
3209 auto haveMessage =
overlay_.relay(*packet, key, val->getSignerPublic());
3210 if (!haveMessage.empty())
3213 key, val->getSignerPublic(), std::move(haveMessage), protocol::mtVALIDATION);
3219 JLOG(
pJournal_.trace()) <<
"Exception processing validation: " << ex.
what();
3220 using namespace std::string_literals;
3235 if (p->hasTxSet(rootHash) && p.get() != skip)
3237 auto score = p->getScore(
true);
3238 if (!ret || (score > retScore))
3263 if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
3265 auto score = p->getScore(
true);
3266 if (!ret || (score > retScore))
3280 protocol::TMLedgerData& ledgerData)
3282 JLOG(
pJournal_.trace()) <<
"sendLedgerBase: Base data";
3285 addRaw(ledger->header(), s);
3288 auto const& stateMap{ledger->stateMap()};
3294 stateMap.serializeRoot(
root);
3295 ledgerData.add_nodes()->set_nodedata(
root.getDataPtr(),
root.getLength());
3299 auto const& txMap{ledger->txMap()};
3304 txMap.serializeRoot(
root);
3305 ledgerData.add_nodes()->set_nodedata(
root.getDataPtr(),
root.getLength());
3317 JLOG(
pJournal_.trace()) <<
"getLedger: Ledger";
3321 if (m->has_ledgerhash())
3325 ledger =
app_.getLedgerMaster().getLedgerByHash(ledgerHash);
3328 JLOG(
pJournal_.trace()) <<
"getLedger: Don't have ledger with hash " << ledgerHash;
3330 if (m->has_querytype() && !m->has_requestcookie())
3334 overlay_, ledgerHash, m->has_ledgerseq() ? m->ledgerseq() : 0,
this))
3336 m->set_requestcookie(
id());
3338 JLOG(
pJournal_.debug()) <<
"getLedger: Request relayed to peer";
3342 JLOG(
pJournal_.trace()) <<
"getLedger: Failed to find peer to relay request";
3346 else if (m->has_ledgerseq())
3349 if (m->ledgerseq() <
app_.getLedgerMaster().getEarliestFetch())
3351 JLOG(
pJournal_.debug()) <<
"getLedger: Early ledger sequence request";
3355 ledger =
app_.getLedgerMaster().getLedgerBySeq(m->ledgerseq());
3359 <<
"getLedger: Don't have ledger with sequence " << m->ledgerseq();
3363 else if (m->has_ltype() && m->ltype() == protocol::ltCLOSED)
3365 ledger =
app_.getLedgerMaster().getClosedLedger();
3371 auto const ledgerSeq{ledger->header().seq};
3372 if (m->has_ledgerseq())
3374 if (ledgerSeq != m->ledgerseq())
3377 if (!m->has_requestcookie())
3381 JLOG(
pJournal_.warn()) <<
"getLedger: Invalid ledger sequence " << ledgerSeq;
3384 else if (ledgerSeq <
app_.getLedgerMaster().getEarliestFetch())
3387 JLOG(
pJournal_.debug()) <<
"getLedger: Early ledger sequence request " << ledgerSeq;
3392 JLOG(
pJournal_.debug()) <<
"getLedger: Unable to find ledger";
3401 JLOG(
pJournal_.trace()) <<
"getTxSet: TX set";
3407 if (m->has_querytype() && !m->has_requestcookie())
3412 m->set_requestcookie(
id());
3414 JLOG(
pJournal_.debug()) <<
"getTxSet: Request relayed";
3418 JLOG(
pJournal_.debug()) <<
"getTxSet: Failed to find relay peer";
3423 JLOG(
pJournal_.debug()) <<
"getTxSet: Failed to find TX set";
3437 SHAMap const* map{
nullptr};
3438 protocol::TMLedgerData ledgerData;
3439 bool fatLeaves{
true};
3440 auto const itype{m->itype()};
3442 if (itype == protocol::liTS_CANDIDATE)
3444 if (sharedMap =
getTxSet(m); !sharedMap)
3446 map = sharedMap.
get();
3449 ledgerData.set_ledgerseq(0);
3450 ledgerData.set_ledgerhash(m->ledgerhash());
3451 ledgerData.set_type(protocol::liTS_CANDIDATE);
3452 if (m->has_requestcookie())
3453 ledgerData.set_requestcookie(m->requestcookie());
3462 JLOG(
pJournal_.debug()) <<
"processLedgerRequest: Large send queue";
3465 if (
app_.getFeeTrack().isLoadedLocal() && !
cluster())
3467 JLOG(
pJournal_.debug()) <<
"processLedgerRequest: Too busy";
3475 auto const ledgerHash{ledger->header().hash};
3476 ledgerData.set_ledgerhash(ledgerHash.begin(), ledgerHash.size());
3477 ledgerData.set_ledgerseq(ledger->header().seq);
3478 ledgerData.set_type(itype);
3479 if (m->has_requestcookie())
3480 ledgerData.set_requestcookie(m->requestcookie());
3484 case protocol::liBASE:
3488 case protocol::liTX_NODE:
3489 map = &ledger->txMap();
3494 case protocol::liAS_NODE:
3495 map = &ledger->stateMap();
3497 <<
"processLedgerRequest: Account state map hash " <<
to_string(map->
getHash());
3502 JLOG(
pJournal_.error()) <<
"processLedgerRequest: Invalid ledger info type";
3509 JLOG(
pJournal_.warn()) <<
"processLedgerRequest: Unable to find map";
3514 if (!nodeIDs.
empty())
3517 auto const queryDepth{m->has_querydepth() ? m->querydepth() : defaultDepth};
3523 for (
auto const& nodeID : nodeIDs)
3532 if (map->
getNodeFat(nodeID, data, fatLeaves, queryDepth))
3535 <<
"processLedgerRequest: getNodeFat got " << data.size() <<
" nodes";
3537 for (
auto const& d : data)
3542 protocol::TMLedgerNode* node{ledgerData.add_nodes()};
3543 node->set_nodedata(d.data.data(), d.data.size());
3548 if (!useLedgerNodeDepth)
3550 node->set_nodeid(d.nodeID.getRawString());
3554 REACHABLE(
"xrpl::PeerImp : emit leaf depth in reply");
3555 node->set_depth(d.nodeID.getDepth());
3559 REACHABLE(
"xrpl::PeerImp : emit inner id in reply");
3560 node->set_id(d.nodeID.getRawString());
3566 JLOG(
pJournal_.warn()) <<
"processLedgerRequest: getNodeFat returns false";
3574 case protocol::liBASE:
3576 info =
"Ledger base";
3579 case protocol::liTX_NODE:
3583 case protocol::liAS_NODE:
3587 case protocol::liTS_CANDIDATE:
3588 info =
"TS candidate";
3596 if (!m->has_ledgerhash())
3597 info +=
", no hash specified";
3600 <<
"processLedgerRequest: getNodeFat with nodeId " << nodeID
3601 <<
" and ledger info type " << info <<
" throws exception: " << e.
what();
3605 JLOG(
pJournal_.info()) <<
"processLedgerRequest: Got request for " << m->nodeids_size()
3606 <<
" node IDs at depth " << queryDepth <<
", return "
3607 << ledgerData.nodes_size() <<
" nodes";
3610 if (ledgerData.nodes_size() == 0)
3643 int const missed =
std::max(0, requested - found);
3644 int const billableMisses =
std::min(missed, billable);
3645 int const billableHits = billable - billableMisses;
3668 static int const kSpRandomMax = 9999;
3672 static int const kSpHaveItem = 10000;
3677 static int const kSpLatency = 30;
3680 static int const kSpNoLatency = 8000;
3682 int score =
randInt(kSpRandomMax);
3685 score += kSpHaveItem;
3695 score -= latency->count() * kSpLatency;
3699 score -= kSpNoLatency;
3709 return latency_ >= kPeerHighLatency;
3715 using namespace std::chrono_literals;
3723 if (timeElapsedInSecs >= 1s)
3725 auto const avgBytes =
accumBytes_ / timeElapsedInSecs.count();
A version-independent IP address and port combination.
static std::optional< Endpoint > fromStringChecked(std::string const &s)
Create an Endpoint from a string.
static Endpoint fromString(std::string const &s)
static BaseUInt fromRaw(Container const &c)
static constexpr std::size_t size()
static std::size_t messageSize(::google::protobuf::Message const &message)
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
Child(OverlayImpl &overlay)
void forEach(UnaryFunc &&f) const
std::uint64_t rollingAvgBytes_
clock_type::time_point intervalStart_
boost::circular_buffer< std::uint64_t > rollingAvg_
void addMessage(std::uint64_t bytes)
std::uint64_t averageBytes() const
std::uint64_t totalBytes() const
std::uint64_t accumBytes_
std::uint64_t totalBytes_
void checkTracking(std::uint32_t validationSeq)
Check if the peer is tracking.
void onTimer(boost::system::error_code const &ec)
std::optional< std::chrono::milliseconds > latency_
void addTxQueue(uint256 const &hash) override
Add transaction's hash to the transactions' hashes queue.
std::string getVersion() const
Return the version of xrpld that the peer is running, if reported.
void onMessage(std::shared_ptr< protocol::TMManifests > const &m)
ProtocolVersion protocol_
bool txReduceRelayEnabled_
void checkTransaction(HashRouterFlags flags, bool checkSignature, std::shared_ptr< STTx const > const &stx, bool batch)
void handleTransaction(std::shared_ptr< protocol::TMTransaction > const &m, bool eraseTxQueue, bool batch)
Called from onMessage(TMTransaction(s)).
http_request_type request_
void removeTxQueue(uint256 const &hash) override
Remove transaction's hash from the transactions' hashes queue.
bool txReduceRelayEnabled() const override
compression::Compressed Compressed
boost::beast::http::fields const & headers_
Compressed compressionEnabled_
std::chrono::steady_clock clock_type
boost::system::error_code error_code
std::shared_ptr< peer_finder::Slot > const slot_
void addLedger(uint256 const &hash, std::scoped_lock< std::mutex > const &lockedRecentLock)
boost::beast::multi_buffer readBuffer_
std::string const & fingerprint() const override
bool ledgerReplayEnabled_
void sendTxQueue() override
Send aggregated transactions' hashes.
struct xrpl::PeerImp::@337373043150231020277011015352151251117171316327 metrics_
beast::ip::Endpoint const remoteAddress_
std::unique_ptr< stream_type > streamPtr_
uint256 closedLedgerHash_
reduce_relay::Squelch< UptimeClock > squelch_
PeerImp(PeerImp const &)=delete
void checkValidation(std::shared_ptr< STValidation > const &val, uint256 const &key, std::shared_ptr< protocol::TMValidation > const &packet)
void cycleStatus() override
std::shared_mutex nameMutex_
std::string domain() const
std::atomic< Tracking > tracking_
void ledgerRange(std::uint32_t &minSeq, std::uint32_t &maxSeq) const override
clock_type::duration uptime() const
beast::WrappedSink pSink_
PublicKey const publicKey_
void processGetObjectByHash(std::shared_ptr< protocol::TMGetObjectByHash > const &m)
Process a generic-query TMGetObjectByHash message.
bool cluster() const override
Returns true if this connection is a member of the cluster.
static resource::Charge computeGetObjectByHashFee(int const requested, int const found)
Compute the per-message resource charge for a TMGetObjectByHash request based on how much work was ac...
std::queue< std::shared_ptr< Message > > sendQueue_
void checkPropose(bool isTrusted, std::shared_ptr< protocol::TMProposeSet > const &packet, RCLCxPeerPos peerPos)
resource::Consumer usage_
void sendLedgerBase(std::shared_ptr< Ledger const > const &ledger, protocol::TMLedgerData &ledgerData)
Peer::id_t id() const override
beast::Journal const pJournal_
static std::string makePrefix(std::string const &fingerprint)
void onShutdown(error_code ec)
void handleHaveTransactions(std::shared_ptr< protocol::TMHaveTransactions > const &m)
Handle protocol message with hashes of transactions that have not been relayed by an upstream node do...
void onMessageUnknown(std::uint16_t type)
void processLedgerRequest(std::shared_ptr< protocol::TMGetLedger > const &m, std::vector< SHAMapNodeID > nodeIDs)
Tracking
Whether the peer's view of the ledger converges or diverges from ours.
protocol::TMStatusChange lastStatus_
clock_type::time_point const creationTime_
LedgerReplayMsgHandler ledgerReplayMsgHandler_
void fail(std::string const &reason)
std::unique_ptr< LoadEvent > loadEvent_
void send(std::shared_ptr< Message > const &m) override
void onMessageBegin(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m, std::size_t size, std::size_t uncompressedSize, bool isCompressed)
void doFetchPack(std::shared_ptr< protocol::TMGetObjectByHash > const &packet)
bool supportsFeature(ProtocolFeature f) const override
std::shared_ptr< Ledger const > getLedger(std::shared_ptr< protocol::TMGetLedger > const &m)
boost::asio::strand< boost::asio::executor > strand_
clock_type::time_point lastPingTime_
boost::circular_buffer< uint256 > recentLedgers_
int getScore(bool haveItem) const override
bool hasTxSet(uint256 const &hash) const override
boost::circular_buffer< uint256 > recentTxSets_
clock_type::time_point trackingTime_
beast::Journal const journal_
bool isHighLatency() const override
void cancelTimer() noexcept
bool hasRange(std::uint32_t uMin, std::uint32_t uMax) override
std::shared_ptr< SHAMap const > getTxSet(std::shared_ptr< protocol::TMGetLedger > const &m) const
uint256 previousLedgerHash_
std::optional< std::uint32_t > lastPingSeq_
void onWriteMessage(error_code ec, std::size_t bytesTransferred)
bool crawl() const
Returns true if this connection will publicly share its IP address.
void onValidatorListMessage(std::string const &messageType, std::string const &manifest, std::uint32_t version, std::vector< ValidatorBlobInfo > const &blobs)
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 doTransactions(std::shared_ptr< protocol::TMGetObjectByHash > const &packet)
Process peer's request to send missing transactions.
std::shared_ptr< peer_finder::Slot > const & slot()
void onReadMessage(error_code ec, std::size_t bytesTransferred)
hash_map< PublicKey, std::size_t > publisherListSequences_
json::Value json() override
bool hasLedger(uint256 const &hash, std::uint32_t seq) const override
boost::asio::basic_waitable_timer< std::chrono::steady_clock > waitable_timer
void onMessageEnd(std::uint16_t type, std::shared_ptr<::google::protobuf::Message > const &m)
std::uint32_t id_t
Uniquely identifies a peer.
Slice slice() const noexcept
A peer's signed, proposed position for use in RCLConsensus.
uint256 const & suppressionID() const
Unique id used by hash router to suppress duplicates.
PublicKey const & publicKey() const
Public key of peer that sent the proposal.
ConsensusProposal< NodeID, uint256, uint256 > Proposal
bool checkSign() const
Verify the signing hash of the proposal.
bool getNodeFat(SHAMapNodeID const &wanted, std::vector< SHAMapNodeData > &data, bool fatLeaves, std::uint32_t depth) const
SHAMapHash getHash() const
void const * getDataPtr() const
std::size_t size() const noexcept
void const * data() const noexcept
An immutable linear range of bytes.
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)
static std::vector< ValidatorBlobInfo > parseBlobs(std::uint32_t version, json::Value const &body)
Pull the blob/signature/manifest information out of the appropriate Json body fields depending on the...
An endpoint that consumes resources.
T duration_cast(T... args)
T emplace_back(T... args)
@ Object
object value (collection of name/value pairs).
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 kMaxTxQueueSize
static constexpr auto kIdled
Charge const kFeeMalformedData
Charge const kFeeHeavyBurdenPeer
Charge const kFeeUselessData
Charge const kFeeRequestNoReply
Charge const kFeeMalformedRequest
Schedule of fees charged for imposing load on the server.
Charge const kFeeInvalidSignature
Charge const kFeeInvalidData
Charge const kFeeModerateBurdenPeer
Charge const kFeeTrivialPeer
static constexpr auto kSoftMaxReplyNodes
The soft cap on the number of ledger entries in a single reply.
static constexpr auto kBandMediumMax
static constexpr auto kTargetSendQueue
How many messages we consider reasonable sustained on a send queue.
static constexpr auto kCostPerLookupHit
Cost of one cache-hit lookup.
static constexpr auto kCostBandLarge
static constexpr auto kFreeObjectsPerRequest
TMGetObjectByHash differential pricing.
static constexpr auto kHardMaxReplyNodes
The hard cap on the number of ledger entries in a single reply.
static constexpr std::uint32_t kConvergedLedgerLimit
How many ledgers off a server can be and we will still consider it converged.
static constexpr auto kDropSendQueue
How many messages on a send queue before we refuse queries.
static constexpr auto kMaxQueryDepth
The maximum number of levels to search.
static constexpr auto kSendqIntervals
How many timer intervals a sendq has to stay large before we disconnect.
static constexpr auto kBandSmallMax
Cutoffs that decide which size band a request falls into.
constexpr std::size_t kReadBufferBytes
Size of buffer used to read from the socket.
static constexpr auto kCostBandMedium
static constexpr auto kCostPerLookupMiss
Cost of one node-store miss, in units of kCostPerLookupHit.
static constexpr std::uint32_t kDivergedLedgerLimit
How many ledgers off a server has to be before we consider it diverged.
static constexpr auto kCostBandSmall
Size-band surcharges.
static constexpr auto kSendQueueLogFreq
How often to log send queue size.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
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,...
std::string base64Decode(std::string_view data)
constexpr FlagValue tfInnerBatchTxn
bool isCurrent(ValidationParms const &p, NetClock::time_point now, NetClock::time_point signTime, NetClock::time_point seenTime)
Whether a validation is still current.
@ Valid
Signature and local checks are good / passed.
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
std::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::uint32_t LedgerIndex
A ledger index.
Stopwatch & stopwatch()
Returns an instance of a wall clock.
std::string strHex(FwdIt begin, FwdIt end)
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules)
Checks transaction signature and local checks.
@ UnsupportedVersion
List version is not supported.
@ Expired
List is expired, but has the largest non-pending sequence seen so far.
@ SameSequence
Same sequence as current list.
@ KnownSequence
Future sequence already seen.
@ Pending
List will be valid in the future.
@ Invalid
Invalid format or signature.
@ Untrusted
List signed by untrusted publisher key.
@ Stale
Trusted publisher key, but seq is too old.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
static constexpr char kFeatureLedgerReplay[]
Number root(Number f, unsigned d)
constexpr Dest safeCast(Src s) noexcept
static std::shared_ptr< PeerImp > getPeerWithLedger(OverlayImpl &ov, uint256 const &ledgerHash, LedgerIndex ledger, PeerImp const *skip)
std::optional< SHAMapNodeID > getSHAMapNodeID(protocol::TMLedgerNode const &ledgerNode, SHAMapTreeNode const &treeNode)
Extracts or reconstructs the SHAMapNodeID from a ledger node proto message.
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
SHAMapTreeNodePtr getTreeNode(std::string_view data)
Deserializes a SHAMapTreeNode from wire format data.
static constexpr char kFeatureTxrr[]
Slice makeSlice(std::array< T, N > const &a)
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.
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
NodeID calcNodeID(PublicKey const &)
Calculate the 160-bit node ID from a node public key.
constexpr ProtocolVersion makeProtocol(std::uint16_t major, std::uint16_t minor)
std::optional< SHAMapNodeID > deserializeSHAMapNodeID(void const *data, std::size_t size)
Return an object representing a serialized SHAMap Node ID.
http_response_type makeResponse(bool crawlPublic, http_request_type const &req, beast::ip::Address publicIp, beast::ip::Address remoteIp, uint256 const &sharedValue, std::optional< std::uint32_t > networkID, ProtocolVersion protocol, Application &app)
Make http response.
std::string getFingerprint(beast::ip::Endpoint const &address, std::optional< PublicKey > const &publicKey=std::nullopt, std::optional< std::string > const &id=std::nullopt)
bool peerFeatureEnabled(Headers const &request, std::string const &feature, std::string value, bool config)
Check if a feature should be enabled for a peer.
@ Malformed
Protocol-level violation; no honest peer would produce this.
@ BadData
Peer reported has_error() (legitimate "cannot fulfill" signal).
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.
std::pair< std::uint16_t, std::uint16_t > ProtocolVersion
Represents a particular version of the peer-to-peer protocol.
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
static bool stringIsUInt256Sized(std::string const &pBuffStr)
static constexpr char kFeatureCompr[]
std::string protocolMessageName(int type)
Returns the name of a protocol message given its type.
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
static constexpr char kFeatureVprr[]
static std::shared_ptr< PeerImp > getPeerWithTree(OverlayImpl &ov, uint256 const &rootHash, PeerImp const *skip)
constexpr bool any(HashRouterFlags flags)
T shared_from_this(T... args)
Options controlling deserialization of a STValidation.
Describes a single consumer.
beast::ip::Endpoint address
Data format for exchanging consumption information across peers.
std::vector< Item > items