20 #include <ripple/app/consensus/RCLValidations.h>
21 #include <ripple/app/ledger/InboundLedgers.h>
22 #include <ripple/app/ledger/InboundTransactions.h>
23 #include <ripple/app/ledger/LedgerMaster.h>
24 #include <ripple/app/misc/HashRouter.h>
25 #include <ripple/app/misc/LoadFeeTrack.h>
26 #include <ripple/app/misc/NetworkOPs.h>
27 #include <ripple/app/misc/Transaction.h>
28 #include <ripple/app/misc/ValidatorList.h>
29 #include <ripple/app/tx/apply.h>
30 #include <ripple/basics/UptimeClock.h>
31 #include <ripple/basics/base64.h>
32 #include <ripple/basics/random.h>
33 #include <ripple/basics/safe_cast.h>
34 #include <ripple/beast/core/LexicalCast.h>
35 #include <ripple/beast/core/SemanticVersion.h>
36 #include <ripple/nodestore/DatabaseShard.h>
37 #include <ripple/overlay/Cluster.h>
38 #include <ripple/overlay/impl/PeerImp.h>
39 #include <ripple/overlay/impl/Tuning.h>
40 #include <ripple/overlay/predicates.h>
41 #include <ripple/protocol/digest.h>
43 #include <boost/algorithm/clamp.hpp>
44 #include <boost/algorithm/string.hpp>
45 #include <boost/algorithm/string/predicate.hpp>
46 #include <boost/beast/core/ostream.hpp>
54 using namespace std::chrono_literals;
79 , sink_(app_.journal(
"Peer"), makePrefix(id))
80 , p_sink_(app_.journal(
"Protocol"), makePrefix(id))
83 , stream_ptr_(
std::move(stream_ptr))
84 , socket_(stream_ptr_->next_layer().socket())
85 , stream_(*stream_ptr_)
86 , strand_(socket_.get_executor())
88 , remote_address_(slot->remote_endpoint())
92 , tracking_(Tracking::unknown)
93 , trackingTime_(clock_type::now())
94 , publicKey_(publicKey)
95 , lastPingTime_(clock_type::now())
96 , creationTime_(clock_type::now())
97 , squelch_(app_.journal(
"Squelch"))
101 , request_(std::move(request))
103 , compressionEnabled_(
108 app_.config().COMPRESSION)
114 app_.config().VP_REDUCE_RELAY_ENABLE))
116 JLOG(journal_.debug()) <<
" compression enabled "
117 << (compressionEnabled_ == Compressed::On)
118 <<
" vp reduce-relay enabled "
119 << vpReduceRelayEnabled_ <<
" on " << remote_address_
125 const bool inCluster{
cluster()};
148 if (!
strand_.running_in_this_thread())
151 auto parseLedgerHash =
152 [](
std::string const& value) -> boost::optional<uint256> {
162 boost::optional<uint256> closed;
163 boost::optional<uint256> previous;
165 if (
auto const iter =
headers_.find(
"Closed-Ledger");
168 closed = parseLedgerHash(iter->value().to_string());
171 fail(
"Malformed handshake data (1)");
174 if (
auto const iter =
headers_.find(
"Previous-Ledger");
177 previous = parseLedgerHash(iter->value().to_string());
180 fail(
"Malformed handshake data (2)");
183 if (previous && !closed)
184 fail(
"Malformed handshake data (3)");
206 if (!
strand_.running_in_this_thread())
232 if (!
strand_.running_in_this_thread())
239 auto validator = m->getValidatorKey();
240 if (validator && !
squelch_.expireSquelch(*validator))
244 safe_cast<TrafficCount::category>(m->getCategory()),
262 <<
" sendq: " << sendq_size;
270 boost::asio::async_write(
279 std::placeholders::_1,
280 std::placeholders::_2)));
287 strand_.running_in_this_thread())
291 fail(
"charge: Resources");
300 auto const iter =
headers_.find(
"Crawl");
303 return boost::iequals(iter->value(),
"public");
316 return headers_[
"User-Agent"].to_string();
317 return headers_[
"Server"].to_string();
329 ret[jss::inbound] =
true;
333 ret[jss::cluster] =
true;
341 ret[jss::server_domain] =
domain();
344 ret[jss::network_id] = nid;
349 ret[jss::version] = version;
360 std::chrono::duration_cast<std::chrono::seconds>(
uptime()).count());
365 if ((minSeq != 0) || (maxSeq != 0))
366 ret[jss::complete_ledgers] =
372 ret[jss::track] =
"diverged";
376 ret[jss::track] =
"unknown";
385 protocol::TMStatusChange last_status;
392 if (closedLedgerHash != beast::zero)
393 ret[jss::ledger] =
to_string(closedLedgerHash);
395 if (last_status.has_newstatus())
397 switch (last_status.newstatus())
399 case protocol::nsCONNECTING:
400 ret[jss::status] =
"connecting";
403 case protocol::nsCONNECTED:
404 ret[jss::status] =
"connected";
407 case protocol::nsMONITORING:
408 ret[jss::status] =
"monitoring";
411 case protocol::nsVALIDATING:
412 ret[jss::status] =
"validating";
415 case protocol::nsSHUTTING:
416 ret[jss::status] =
"shutting";
421 <<
"Unknown status: " << last_status.newstatus();
426 ret[jss::metrics][jss::total_bytes_recv] =
428 ret[jss::metrics][jss::total_bytes_sent] =
430 ret[jss::metrics][jss::avg_bps_recv] =
432 ret[jss::metrics][jss::avg_bps_sent] =
485 return boost::icl::contains(it->second.shardIndexes, shardIndex);
520 assert(
strand_.running_in_this_thread());
542 if (!
strand_.running_in_this_thread())
553 <<
" failed: " << reason;
561 assert(
strand_.running_in_this_thread());
571 boost::optional<RangeSet<std::uint32_t>>
577 return it->second.shardIndexes;
581 boost::optional<hash_map<PublicKey, PeerImp::ShardInfo>>
593 assert(
strand_.running_in_this_thread());
605 stream_.async_shutdown(bind_executor(
615 timer_.expires_from_now(peerTimerInterval, ec);
622 timer_.async_wait(bind_executor(
652 if (ec == boost::asio::error::operation_aborted)
664 fail(
"Large send queue");
670 clock_type::duration duration;
691 fail(
"Ping Timeout");
698 protocol::TMPing message;
699 message.set_type(protocol::TMPing::ptPING);
702 send(std::make_shared<Message>(message, protocol::mtPING));
714 JLOG(
journal_.
error()) <<
"onShutdown: expected error condition";
717 if (ec != boost::asio::error::eof)
718 return fail(
"onShutdown", ec);
735 return fail(
"makeSharedValue: Unexpected failure");
756 auto write_buffer = std::make_shared<boost::beast::multi_buffer>();
769 boost::asio::async_write(
771 write_buffer->data(),
772 boost::asio::transfer_all(),
779 if (ec == boost::asio::error::operation_aborted)
782 return fail(
"onWriteResponse", ec);
783 if (write_buffer->size() == bytes_transferred)
785 return fail(
"Failed to write header");
799 return headers_[
"Server-Domain"].to_string();
841 protocol::TMGetPeerShardInfo tmGPS;
843 send(std::make_shared<Message>(tmGPS, protocol::mtGET_PEER_SHARD_INFO));
854 if (ec == boost::asio::error::operation_aborted)
856 if (ec == boost::asio::error::eof)
862 return fail(
"onReadMessage", ec);
865 if (bytes_transferred > 0)
866 stream <<
"onReadMessage: " << bytes_transferred <<
" bytes";
868 stream <<
"onReadMessage";
871 metrics_.recv.add_message(bytes_transferred);
883 return fail(
"onReadMessage", ec);
888 if (bytes_consumed == 0)
901 std::placeholders::_1,
902 std::placeholders::_2)));
910 if (ec == boost::asio::error::operation_aborted)
913 return fail(
"onWriteMessage", ec);
916 if (bytes_transferred > 0)
917 stream <<
"onWriteMessage: " << bytes_transferred <<
" bytes";
919 stream <<
"onWriteMessage";
922 metrics_.sent.add_message(bytes_transferred);
929 return boost::asio::async_write(
938 std::placeholders::_1,
939 std::placeholders::_2)));
944 return stream_.async_shutdown(bind_executor(
949 std::placeholders::_1)));
978 JLOG(
journal_.
trace()) <<
"onMessageBegin: " << type <<
" " << size <<
" "
979 << uncompressed_size <<
" " << isCompressed;
994 auto const s = m->list_size();
1016 if (m->type() == protocol::TMPing::ptPING)
1020 m->set_type(protocol::TMPing::ptPONG);
1021 send(std::make_shared<Message>(*m, protocol::mtPING));
1025 if (m->type() == protocol::TMPing::ptPONG && m->has_seq())
1035 auto const rtt = std::chrono::round<std::chrono::milliseconds>(
1060 for (
int i = 0; i < m->clusternodes().size(); ++i)
1062 protocol::TMClusterNode
const& node = m->clusternodes(i);
1065 if (node.has_nodename())
1066 name = node.nodename();
1068 auto const publicKey =
1075 auto const reportTime =
1079 *publicKey,
name, node.nodeload(), reportTime);
1083 int loadSources = m->loadsources().size();
1084 if (loadSources != 0)
1087 gossip.
items.reserve(loadSources);
1088 for (
int i = 0; i < m->loadsources().size(); ++i)
1090 protocol::TMLoadSource
const& node = m->loadsources(i);
1095 gossip.
items.push_back(item);
1108 if (status.getReportTime() >= thresh)
1109 fees.push_back(status.getLoadFee());
1114 auto const index = fees.size() / 2;
1116 clusterFee = fees[index];
1145 return badData(
"Invalid peer chain");
1151 auto shards{shardStore->getCompleteShards()};
1152 if (!shards.empty())
1154 protocol::TMPeerShardInfo reply;
1155 reply.set_shardindexes(shards);
1157 if (m->has_lastlink())
1158 reply.set_lastlink(
true);
1160 if (m->peerchain_size() > 0)
1162 for (
int i = 0; i < m->peerchain_size(); ++i)
1165 return badData(
"Invalid peer chain public key");
1168 *reply.mutable_peerchain() = m->peerchain();
1171 send(std::make_shared<Message>(reply, protocol::mtPEER_SHARD_INFO));
1182 m->set_hops(m->hops() - 1);
1184 m->set_lastlink(
true);
1186 m->add_peerchain()->set_nodepubkey(
1190 std::make_shared<Message>(*m, protocol::mtGET_PEER_SHARD_INFO),
1203 if (m->shardindexes().empty())
1204 return badData(
"Missing shard indexes");
1206 return badData(
"Invalid peer chain");
1208 return badData(
"Invalid public key");
1211 if (m->peerchain_size() > 0)
1215 makeSlice(m->peerchain(m->peerchain_size() - 1).nodepubkey())};
1217 return badData(
"Invalid pubKey");
1222 if (!m->has_nodepubkey())
1225 if (!m->has_endpoint())
1231 m->set_endpoint(
"0");
1234 m->mutable_peerchain()->RemoveLast();
1236 std::make_shared<Message>(*m, protocol::mtPEER_SHARD_INFO));
1239 <<
"Relayed TMPeerShardInfo to peer with IP "
1254 if (!
from_string(shardIndexes, m->shardindexes()))
1255 return badData(
"Invalid shard indexes");
1258 boost::optional<std::uint32_t> latestShard;
1260 auto const curLedgerSeq{
1264 earliestShard = shardStore->earliestShardIndex();
1265 if (curLedgerSeq >= shardStore->earliestLedgerSeq())
1266 latestShard = shardStore->seqToShardIndex(curLedgerSeq);
1270 auto const earliestLedgerSeq{
1273 if (curLedgerSeq >= earliestLedgerSeq)
1278 if (boost::icl::first(shardIndexes) < earliestShard ||
1279 (latestShard && boost::icl::last(shardIndexes) > latestShard))
1281 return badData(
"Invalid shard indexes");
1287 if (m->has_endpoint())
1289 if (m->endpoint() !=
"0")
1294 return badData(
"Invalid incoming endpoint: " + m->endpoint());
1295 endpoint = std::move(*result);
1305 if (m->has_nodepubkey())
1316 it->second.endpoint = std::move(endpoint);
1319 it->second.shardIndexes += shardIndexes;
1325 shardInfo.
endpoint = std::move(endpoint);
1327 shardInfo_.emplace(publicKey, std::move(shardInfo));
1332 <<
"Consumed TMPeerShardInfo originating from public key "
1334 << m->shardindexes();
1336 if (m->has_lastlink())
1349 endpoints.
reserve(m->endpoints_v2().size());
1351 for (
auto const& tm : m->endpoints_v2())
1357 << tm.endpoint() <<
"}";
1373 if (!endpoints.
empty())
1388 <<
"Need network ledger";
1396 auto stx = std::make_shared<STTx const>(sit);
1397 uint256 txID = stx->getTransactionID();
1416 bool checkSignature =
true;
1419 if (!m->has_deferred() || !m->deferred())
1423 flags |= SF_TRUSTED;
1430 checkSignature =
false;
1443 <<
"No new transactions until synchronized";
1449 "recvTransaction->checkTransaction",
1454 if (
auto peer = weak.lock())
1455 peer->checkTransaction(flags, checkSignature, stx);
1462 <<
"Transaction invalid: " <<
strHex(m->rawtransaction());
1472 if (
auto peer = weak.
lock())
1480 protocol::TMLedgerData& packet = *m;
1482 if (m->nodes().size() <= 0)
1488 if (m->has_requestcookie())
1494 m->clear_requestcookie();
1496 std::make_shared<Message>(packet, protocol::mtLEDGER_DATA));
1500 JLOG(
p_journal_.
info()) <<
"Unable to route TX/ledger data reply";
1508 JLOG(
p_journal_.
warn()) <<
"TX candidate reply with invalid hash size";
1513 uint256 const hash{m->ledgerhash()};
1515 if (m->type() == protocol::liTS_CANDIDATE)
1521 if (
auto peer = weak.
lock())
1522 peer->app_.getInboundTransactions().gotData(hash, peer, m);
1537 protocol::TMProposeSet&
set = *m;
1543 if ((boost::algorithm::clamp(sig.size(), 64, 72) != sig.size()) ||
1559 uint256 const proposeHash{
set.currenttxhash()};
1560 uint256 const prevLedger{
set.previousledger()};
1573 if (
auto [added, relayed] =
1582 suppression, publicKey,
id_, protocol::mtPROPOSE_LEDGER);
1594 <<
"Proposal: Dropping untrusted (peer divergence)";
1606 <<
"Proposal: " << (isTrusted ?
"trusted" :
"untrusted");
1623 "recvPropose->checkPropose",
1625 if (
auto peer = weak.lock())
1626 peer->checkPropose(job, m,
proposal);
1635 if (!m->has_networktime())
1640 if (!
last_status_.has_newstatus() || m->has_newstatus())
1645 protocol::NodeStatus status =
last_status_.newstatus();
1647 m->set_newstatus(status);
1651 if (m->newevent() == protocol::neLOST_SYNC)
1653 bool outOfSync{
false};
1674 bool const peerChangedLedgers{
1681 if (peerChangedLedgers)
1692 if (m->has_ledgerhashprevious() &&
1703 if (peerChangedLedgers)
1713 if (m->has_firstseq() && m->has_lastseq())
1724 if (m->has_ledgerseq() &&
1734 if (m->has_newstatus())
1736 switch (m->newstatus())
1738 case protocol::nsCONNECTING:
1739 j[jss::status] =
"CONNECTING";
1741 case protocol::nsCONNECTED:
1742 j[jss::status] =
"CONNECTED";
1744 case protocol::nsMONITORING:
1745 j[jss::status] =
"MONITORING";
1747 case protocol::nsVALIDATING:
1748 j[jss::status] =
"VALIDATING";
1750 case protocol::nsSHUTTING:
1751 j[jss::status] =
"SHUTTING";
1756 if (m->has_newevent())
1758 switch (m->newevent())
1760 case protocol::neCLOSING_LEDGER:
1761 j[jss::action] =
"CLOSING_LEDGER";
1763 case protocol::neACCEPTED_LEDGER:
1764 j[jss::action] =
"ACCEPTED_LEDGER";
1766 case protocol::neSWITCHED_LEDGER:
1767 j[jss::action] =
"SWITCHED_LEDGER";
1769 case protocol::neLOST_SYNC:
1770 j[jss::action] =
"LOST_SYNC";
1775 if (m->has_ledgerseq())
1777 j[jss::ledger_index] = m->ledgerseq();
1780 if (m->has_ledgerhash())
1782 uint256 closedLedgerHash{};
1784 std::lock_guard sl(recentLock_);
1785 closedLedgerHash = closedLedgerHash_;
1787 j[jss::ledger_hash] =
to_string(closedLedgerHash);
1790 if (m->has_networktime())
1792 j[jss::date] = Json::UInt(m->networktime());
1795 if (m->has_firstseq() && m->has_lastseq())
1797 j[jss::ledger_index_min] = Json::UInt(m->firstseq());
1798 j[jss::ledger_index_max] = Json::UInt(m->lastseq());
1814 serverSeq = maxLedger_;
1820 checkTracking(serverSeq, validationSeq);
1829 if (
diff < Tuning::convergedLedgerLimit)
1832 tracking_ = Tracking::converged;
1835 if ((
diff > Tuning::divergedLedgerLimit) &&
1836 (tracking_.load() != Tracking::diverged))
1841 tracking_ = Tracking::diverged;
1842 trackingTime_ = clock_type::now();
1851 fee_ = Resource::feeInvalidRequest;
1855 uint256 const hash{m->hash()};
1857 if (m->status() == protocol::tsHAVE)
1861 if (
std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
1862 recentTxSets_.end())
1864 fee_ = Resource::feeUnwantedData;
1868 recentTxSets_.push_back(hash);
1873 PeerImp::onValidatorListMessage(
1883 JLOG(p_journal_.warn()) <<
"Ignored malformed " << messageType
1884 <<
" from peer " << remote_address_;
1886 fee_ = Resource::feeHighBurdenPeer;
1892 JLOG(p_journal_.debug())
1893 <<
"Received " << messageType <<
" from " << remote_address_.to_string()
1894 <<
" (" << id_ <<
")";
1896 if (!app_.getHashRouter().addSuppressionPeer(hash, id_))
1898 JLOG(p_journal_.debug())
1899 << messageType <<
": received duplicate " << messageType;
1903 fee_ = Resource::feeUnwantedData;
1907 auto const applyResult = app_.validators().applyListsAndBroadcast(
1911 remote_address_.to_string(),
1914 app_.getHashRouter(),
1917 JLOG(p_journal_.debug())
1918 <<
"Processed " << messageType <<
" version " << version <<
" from "
1919 << (applyResult.publisherKey ?
strHex(*applyResult.publisherKey)
1920 :
"unknown or invalid publisher")
1921 <<
" from " << remote_address_.to_string() <<
" (" << id_
1922 <<
") with best result " << to_string(applyResult.bestDisposition());
1925 switch (applyResult.bestDisposition())
1928 case ListDisposition::accepted:
1930 case ListDisposition::expired:
1932 case ListDisposition::pending: {
1935 assert(applyResult.publisherKey);
1936 auto const& pubKey = *applyResult.publisherKey;
1938 if (
auto const iter = publisherListSequences_.find(pubKey);
1939 iter != publisherListSequences_.end())
1941 assert(iter->second < applyResult.sequence);
1944 publisherListSequences_[pubKey] = applyResult.sequence;
1947 case ListDisposition::same_sequence:
1948 case ListDisposition::known_sequence:
1952 assert(applyResult.sequence && applyResult.publisherKey);
1954 publisherListSequences_[*applyResult.publisherKey] <=
1955 applyResult.sequence);
1960 case ListDisposition::stale:
1961 case ListDisposition::untrusted:
1962 case ListDisposition::invalid:
1963 case ListDisposition::unsupported_version:
1970 switch (applyResult.worstDisposition())
1972 case ListDisposition::accepted:
1973 case ListDisposition::expired:
1974 case ListDisposition::pending:
1977 case ListDisposition::same_sequence:
1978 case ListDisposition::known_sequence:
1982 fee_ = Resource::feeUnwantedData;
1984 case ListDisposition::stale:
1987 fee_ = Resource::feeBadData;
1989 case ListDisposition::untrusted:
1993 fee_ = Resource::feeUnwantedData;
1995 case ListDisposition::invalid:
1997 fee_ = Resource::feeInvalidSignature;
1999 case ListDisposition::unsupported_version:
2002 fee_ = Resource::feeBadData;
2009 for (
auto const [disp, count] : applyResult.dispositions)
2014 case ListDisposition::accepted:
2015 JLOG(p_journal_.debug())
2016 <<
"Applied " << count <<
" new " << messageType
2017 <<
"(s) from peer " << remote_address_;
2020 case ListDisposition::expired:
2021 JLOG(p_journal_.debug())
2022 <<
"Applied " << count <<
" expired " << messageType
2023 <<
"(s) from peer " << remote_address_;
2026 case ListDisposition::pending:
2027 JLOG(p_journal_.debug())
2028 <<
"Processed " << count <<
" future " << messageType
2029 <<
"(s) from peer " << remote_address_;
2031 case ListDisposition::same_sequence:
2032 JLOG(p_journal_.warn())
2033 <<
"Ignored " << count <<
" " << messageType
2034 <<
"(s) with current sequence from peer "
2037 case ListDisposition::known_sequence:
2038 JLOG(p_journal_.warn())
2039 <<
"Ignored " << count <<
" " << messageType
2040 <<
"(s) with future sequence from peer " << remote_address_;
2042 case ListDisposition::stale:
2043 JLOG(p_journal_.warn())
2044 <<
"Ignored " << count <<
"stale " << messageType
2045 <<
"(s) from peer " << remote_address_;
2047 case ListDisposition::untrusted:
2048 JLOG(p_journal_.warn())
2049 <<
"Ignored " << count <<
" untrusted " << messageType
2050 <<
"(s) from peer " << remote_address_;
2052 case ListDisposition::unsupported_version:
2053 JLOG(p_journal_.warn())
2054 <<
"Ignored " << count <<
"unsupported version "
2055 << messageType <<
"(s) from peer " << remote_address_;
2057 case ListDisposition::invalid:
2058 JLOG(p_journal_.warn())
2059 <<
"Ignored " << count <<
"invalid " << messageType
2060 <<
"(s) from peer " << remote_address_;
2073 if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
2075 JLOG(p_journal_.debug())
2076 <<
"ValidatorList: received validator list from peer using "
2077 <<
"protocol version " << to_string(protocol_)
2078 <<
" which shouldn't support this feature.";
2079 fee_ = Resource::feeUnwantedData;
2082 onValidatorListMessage(
2086 ValidatorList::parseBlobs(*m));
2090 JLOG(p_journal_.warn()) <<
"ValidatorList: Exception, " << e.
what()
2091 <<
" from peer " << remote_address_;
2092 fee_ = Resource::feeBadData;
2102 if (!supportsFeature(ProtocolFeature::ValidatorList2Propagation))
2104 JLOG(p_journal_.debug())
2105 <<
"ValidatorListCollection: received validator list from peer "
2106 <<
"using protocol version " << to_string(protocol_)
2107 <<
" which shouldn't support this feature.";
2108 fee_ = Resource::feeUnwantedData;
2111 else if (m->version() < 2)
2113 JLOG(p_journal_.debug())
2114 <<
"ValidatorListCollection: received invalid validator list "
2116 << m->version() <<
" from peer using protocol version "
2117 << to_string(protocol_);
2118 fee_ = Resource::feeBadData;
2121 onValidatorListMessage(
2122 "ValidatorListCollection",
2125 ValidatorList::parseBlobs(*m));
2129 JLOG(p_journal_.warn()) <<
"ValidatorListCollection: Exception, "
2130 << e.
what() <<
" from peer " << remote_address_;
2131 fee_ = Resource::feeBadData;
2138 auto const closeTime = app_.timeKeeper().closeTime();
2140 if (m->validation().size() < 50)
2142 JLOG(p_journal_.warn()) <<
"Validation: Too small";
2143 fee_ = Resource::feeInvalidRequest;
2152 val = std::make_shared<STValidation>(
2156 app_.validatorManifests().getMasterKey(pk));
2159 val->setSeen(closeTime);
2163 app_.getValidations().parms(),
2164 app_.timeKeeper().closeTime(),
2166 val->getSeenTime()))
2168 JLOG(p_journal_.trace()) <<
"Validation: Not current";
2169 fee_ = Resource::feeUnwantedData;
2174 if (
auto [added, relayed] =
2175 app_.getHashRouter().addSuppressionPeerWithStatus(key, id_);
2182 if (reduceRelayReady() && relayed &&
2183 (
stopwatch().now() - *relayed) < reduce_relay::IDLED)
2184 overlay_.updateSlotAndSquelch(
2185 key, val->getSignerPublic(), id_, protocol::mtVALIDATION);
2186 JLOG(p_journal_.trace()) <<
"Validation: duplicate";
2190 auto const isTrusted =
2191 app_.validators().trusted(val->getSignerPublic());
2193 if (!isTrusted && (tracking_.load() == Tracking::diverged))
2195 JLOG(p_journal_.debug())
2196 <<
"Validation: dropping untrusted from diverged peer";
2198 if (isTrusted || cluster() || !app_.getFeeTrack().isLoadedLocal())
2201 app_.getJobQueue().addJob(
2203 "recvValidation->checkValidation",
2204 [weak, val, m](
Job&) {
2205 if (
auto peer = weak.
lock())
2206 peer->checkValidation(val, m);
2211 JLOG(p_journal_.debug()) <<
"Validation: Dropping UNTRUSTED (load)";
2216 JLOG(p_journal_.warn())
2217 <<
"Exception processing validation: " << e.
what();
2218 fee_ = Resource::feeInvalidRequest;
2225 protocol::TMGetObjectByHash& packet = *m;
2230 if (send_queue_.size() >= Tuning::dropSendQueue)
2232 JLOG(p_journal_.debug()) <<
"GetObject: Large send queue";
2236 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2242 fee_ = Resource::feeMediumBurdenPeer;
2244 protocol::TMGetObjectByHash reply;
2246 reply.set_query(
false);
2248 if (packet.has_seq())
2249 reply.set_seq(packet.seq());
2251 reply.set_type(packet.type());
2253 if (packet.has_ledgerhash())
2257 fee_ = Resource::feeInvalidRequest;
2261 reply.set_ledgerhash(packet.ledgerhash());
2265 for (
int i = 0; i < packet.objects_size(); ++i)
2267 auto const& obj = packet.objects(i);
2270 uint256 const hash{obj.hash()};
2273 std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2274 auto nodeObject{app_.getNodeStore().fetchNodeObject(hash, seq)};
2277 if (
auto shardStore = app_.getShardStore())
2279 if (seq >= shardStore->earliestLedgerSeq())
2280 nodeObject = shardStore->fetchNodeObject(hash, seq);
2285 protocol::TMIndexedObject& newObj = *reply.add_objects();
2286 newObj.set_hash(hash.begin(), hash.size());
2288 &nodeObject->getData().front(),
2289 nodeObject->getData().size());
2291 if (obj.has_nodeid())
2292 newObj.set_index(obj.nodeid());
2293 if (obj.has_ledgerseq())
2294 newObj.set_ledgerseq(obj.ledgerseq());
2301 JLOG(p_journal_.trace()) <<
"GetObj: " << reply.objects_size() <<
" of "
2302 << packet.objects_size();
2303 send(std::make_shared<Message>(reply, protocol::mtGET_OBJECTS));
2310 bool progress =
false;
2312 for (
int i = 0; i < packet.objects_size(); ++i)
2314 const protocol::TMIndexedObject& obj = packet.objects(i);
2318 if (obj.has_ledgerseq())
2320 if (obj.ledgerseq() != pLSeq)
2322 if (pLDo && (pLSeq != 0))
2324 JLOG(p_journal_.debug())
2325 <<
"GetObj: Full fetch pack for " << pLSeq;
2327 pLSeq = obj.ledgerseq();
2328 pLDo = !app_.getLedgerMaster().haveLedger(pLSeq);
2332 JLOG(p_journal_.debug())
2333 <<
"GetObj: Late fetch pack for " << pLSeq;
2342 uint256 const hash{obj.hash()};
2344 app_.getLedgerMaster().addFetchPack(
2346 std::make_shared<Blob>(
2347 obj.data().begin(), obj.data().end()));
2352 if (pLDo && (pLSeq != 0))
2354 JLOG(p_journal_.debug())
2355 <<
"GetObj: Partial fetch pack for " << pLSeq;
2357 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2358 app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2365 using on_message_fn =
2367 if (!strand_.running_in_this_thread())
2371 (on_message_fn)&PeerImp::onMessage, shared_from_this(), m));
2373 if (!m->has_validatorpubkey())
2375 charge(Resource::feeBadData);
2378 auto validator = m->validatorpubkey();
2382 charge(Resource::feeBadData);
2388 if (key == app_.getValidationPublicKey())
2390 JLOG(p_journal_.debug())
2391 <<
"onMessage: TMSquelch discarding validator's squelch " << slice;
2396 m->has_squelchduration() ? m->squelchduration() : 0;
2398 squelch_.removeSquelch(key);
2400 charge(Resource::feeBadData);
2402 JLOG(p_journal_.debug())
2403 <<
"onMessage: TMSquelch " << slice <<
" " << id() <<
" " << duration;
2415 (void)lockedRecentLock;
2417 if (
std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
2418 recentLedgers_.end())
2421 recentLedgers_.push_back(hash);
2430 if (app_.getFeeTrack().isLoadedLocal() ||
2431 (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2432 (app_.getJobQueue().getJobCount(
jtPACK) > 10))
2434 JLOG(p_journal_.info()) <<
"Too busy to make fetch pack";
2440 JLOG(p_journal_.warn()) <<
"FetchPack hash size malformed";
2441 fee_ = Resource::feeInvalidRequest;
2445 fee_ = Resource::feeHighBurdenPeer;
2447 uint256 const hash{packet->ledgerhash()};
2450 auto elapsed = UptimeClock::now();
2451 auto const pap = &app_;
2452 app_.getJobQueue().addJob(
2453 jtPACK,
"MakeFetchPack", [pap, weak, packet, hash, elapsed](
Job&) {
2454 pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
2459 PeerImp::checkTransaction(
2461 bool checkSignature,
2470 app_.getLedgerMaster().getValidLedgerIndex()))
2472 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2473 charge(Resource::feeUnwantedData);
2481 app_.getHashRouter(),
2483 app_.getLedgerMaster().getValidatedRules(),
2485 valid != Validity::Valid)
2487 if (!validReason.empty())
2489 JLOG(p_journal_.trace())
2490 <<
"Exception checking transaction: " << validReason;
2494 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2495 charge(Resource::feeInvalidSignature);
2502 app_.getHashRouter(), stx->getTransactionID(), Validity::Valid);
2506 auto tx = std::make_shared<Transaction>(stx, reason, app_);
2508 if (tx->getStatus() ==
INVALID)
2510 if (!reason.
empty())
2512 JLOG(p_journal_.trace())
2513 <<
"Exception checking transaction: " << reason;
2515 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2516 charge(Resource::feeInvalidSignature);
2520 bool const trusted(flags & SF_TRUSTED);
2521 app_.getOPs().processTransaction(
2522 tx, trusted,
false, NetworkOPs::FailHard::no);
2526 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2527 charge(Resource::feeBadData);
2533 PeerImp::checkPropose(
2540 JLOG(p_journal_.trace())
2541 <<
"Checking " << (isTrusted ?
"trusted" :
"UNTRUSTED") <<
" proposal";
2547 JLOG(p_journal_.warn()) <<
"Proposal fails sig check";
2548 charge(Resource::feeInvalidSignature);
2555 relay = app_.getOPs().processTrustedProposal(peerPos);
2557 relay = app_.config().RELAY_UNTRUSTED_PROPOSALS || cluster();
2565 auto haveMessage = app_.overlay().relay(
2567 if (reduceRelayReady() && !haveMessage.empty())
2568 overlay_.updateSlotAndSquelch(
2571 std::move(haveMessage),
2572 protocol::mtPROPOSE_LEDGER);
2577 PeerImp::checkValidation(
2584 if (!cluster() && !val->isValid())
2586 JLOG(p_journal_.warn()) <<
"Validation is invalid";
2587 charge(Resource::feeInvalidRequest);
2594 auto const suppression =
2601 overlay_.relay(*packet, suppression, val->getSignerPublic());
2602 if (reduceRelayReady() && !haveMessage.empty())
2604 overlay_.updateSlotAndSquelch(
2606 val->getSignerPublic(),
2607 std::move(haveMessage),
2608 protocol::mtVALIDATION);
2614 JLOG(p_journal_.trace()) <<
"Exception processing validation";
2615 charge(Resource::feeInvalidRequest);
2629 if (p->hasTxSet(rootHash) && p.get() != skip)
2631 auto score = p->getScore(true);
2632 if (!ret || (score > retScore))
2657 if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
2659 auto score = p->getScore(true);
2660 if (!ret || (score > retScore))
2675 protocol::TMGetLedger& packet = *m;
2677 SHAMap const* map =
nullptr;
2678 protocol::TMLedgerData reply;
2679 bool fatLeaves =
true;
2682 if (packet.has_requestcookie())
2683 reply.set_requestcookie(packet.requestcookie());
2687 if (packet.itype() == protocol::liTS_CANDIDATE)
2690 JLOG(p_journal_.trace()) <<
"GetLedger: Tx candidate set";
2692 if (!packet.has_ledgerhash() ||
2695 charge(Resource::feeInvalidRequest);
2696 JLOG(p_journal_.warn()) <<
"GetLedger: Tx candidate set invalid";
2700 uint256 const txHash{packet.ledgerhash()};
2702 shared = app_.getInboundTransactions().getSet(txHash,
false);
2707 if (packet.has_querytype() && !packet.has_requestcookie())
2709 JLOG(p_journal_.debug()) <<
"GetLedger: Routing Tx set request";
2713 packet.set_requestcookie(
id());
2714 v->send(std::make_shared<Message>(
2715 packet, protocol::mtGET_LEDGER));
2719 JLOG(p_journal_.info()) <<
"GetLedger: Route TX set failed";
2723 JLOG(p_journal_.debug()) <<
"GetLedger: Can't provide map ";
2724 charge(Resource::feeInvalidRequest);
2728 reply.set_ledgerseq(0);
2729 reply.set_ledgerhash(txHash.begin(), txHash.size());
2730 reply.set_type(protocol::liTS_CANDIDATE);
2735 if (send_queue_.size() >= Tuning::dropSendQueue)
2737 JLOG(p_journal_.debug()) <<
"GetLedger: Large send queue";
2741 if (app_.getFeeTrack().isLoadedLocal() && !cluster())
2743 JLOG(p_journal_.debug()) <<
"GetLedger: Too busy";
2748 JLOG(p_journal_.trace()) <<
"GetLedger: Received";
2750 if (packet.has_ledgerhash())
2754 charge(Resource::feeInvalidRequest);
2755 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid request";
2759 uint256 const ledgerhash{packet.ledgerhash()};
2760 logMe +=
"LedgerHash:";
2761 logMe += to_string(ledgerhash);
2762 ledger = app_.getLedgerMaster().getLedgerByHash(ledgerhash);
2764 if (!ledger && packet.has_ledgerseq())
2766 if (
auto shardStore = app_.getShardStore())
2768 auto seq = packet.ledgerseq();
2769 if (seq >= shardStore->earliestLedgerSeq())
2770 ledger = shardStore->fetchLedger(ledgerhash, seq);
2776 JLOG(p_journal_.trace())
2777 <<
"GetLedger: Don't have " << ledgerhash;
2781 (packet.has_querytype() && !packet.has_requestcookie()))
2788 packet.has_ledgerseq() ? packet.ledgerseq() : 0,
2792 JLOG(p_journal_.trace()) <<
"GetLedger: Cannot route";
2796 packet.set_requestcookie(
id());
2798 std::make_shared<Message>(packet, protocol::mtGET_LEDGER));
2799 JLOG(p_journal_.debug()) <<
"GetLedger: Request routed";
2803 else if (packet.has_ledgerseq())
2805 if (packet.ledgerseq() < app_.getLedgerMaster().getEarliestFetch())
2807 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2810 ledger = app_.getLedgerMaster().getLedgerBySeq(packet.ledgerseq());
2813 JLOG(p_journal_.debug())
2814 <<
"GetLedger: Don't have " << packet.ledgerseq();
2817 else if (packet.has_ltype() && (packet.ltype() == protocol::ltCLOSED))
2819 ledger = app_.getLedgerMaster().getClosedLedger();
2820 assert(!ledger->open());
2824 if (ledger && ledger->info().open)
2825 ledger = app_.getLedgerMaster ().getLedgerBySeq (
2826 ledger->info().seq - 1);
2831 charge(Resource::feeInvalidRequest);
2832 JLOG(p_journal_.warn()) <<
"GetLedger: Unknown request";
2837 (packet.has_ledgerseq() &&
2838 (packet.ledgerseq() != ledger->info().seq)))
2840 charge(Resource::feeInvalidRequest);
2844 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid sequence";
2849 if (!packet.has_ledgerseq() &&
2850 (ledger->info().seq < app_.getLedgerMaster().getEarliestFetch()))
2852 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2857 auto const lHash = ledger->info().hash;
2858 reply.set_ledgerhash(lHash.begin(), lHash.size());
2859 reply.set_ledgerseq(ledger->info().seq);
2860 reply.set_type(packet.itype());
2862 if (packet.itype() == protocol::liBASE)
2865 JLOG(p_journal_.trace()) <<
"GetLedger: Base data";
2867 addRaw(ledger->info(), nData);
2868 reply.add_nodes()->set_nodedata(
2871 auto const& stateMap = ledger->stateMap();
2872 if (stateMap.getHash() != beast::zero)
2877 stateMap.serializeRoot(rootNode);
2878 reply.add_nodes()->set_nodedata(
2881 if (ledger->info().txHash != beast::zero)
2883 auto const& txMap = ledger->txMap();
2884 if (txMap.getHash() != beast::zero)
2888 txMap.serializeRoot(rootNode);
2889 reply.add_nodes()->set_nodedata(
2896 std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
2901 if (packet.itype() == protocol::liTX_NODE)
2903 map = &ledger->txMap();
2905 logMe += to_string(map->
getHash());
2907 else if (packet.itype() == protocol::liAS_NODE)
2909 map = &ledger->stateMap();
2911 logMe += to_string(map->
getHash());
2915 if (!map || (packet.nodeids_size() == 0))
2917 JLOG(p_journal_.warn()) <<
"GetLedger: Can't find map or empty request";
2918 charge(Resource::feeInvalidRequest);
2922 JLOG(p_journal_.trace()) <<
"GetLedger: " << logMe;
2924 auto const depth = packet.has_querydepth()
2925 ? (
std::min(packet.querydepth(), 3u))
2926 : (isHighLatency() ? 2 : 1);
2929 (i < packet.nodeids().size() &&
2930 (reply.nodes().size() < Tuning::maxReplyNodes));
2937 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid node " << logMe;
2938 charge(Resource::feeBadData);
2947 if (map->
getNodeFat(*mn, nodeIDs, rawNodes, fatLeaves, depth))
2949 assert(nodeIDs.
size() == rawNodes.
size());
2950 JLOG(p_journal_.trace()) <<
"GetLedger: getNodeFat got "
2951 << rawNodes.
size() <<
" nodes";
2955 for (nodeIDIterator = nodeIDs.
begin(),
2956 rawNodeIterator = rawNodes.
begin();
2957 nodeIDIterator != nodeIDs.
end();
2958 ++nodeIDIterator, ++rawNodeIterator)
2960 protocol::TMLedgerNode* node = reply.add_nodes();
2961 node->set_nodeid(nodeIDIterator->getRawString());
2963 &rawNodeIterator->
front(), rawNodeIterator->
size());
2968 JLOG(p_journal_.warn())
2969 <<
"GetLedger: getNodeFat returns false";
2976 if (packet.itype() == protocol::liTS_CANDIDATE)
2977 info =
"TS candidate";
2978 else if (packet.itype() == protocol::liBASE)
2979 info =
"Ledger base";
2980 else if (packet.itype() == protocol::liTX_NODE)
2982 else if (packet.itype() == protocol::liAS_NODE)
2985 if (!packet.has_ledgerhash())
2986 info +=
", no hash specified";
2988 JLOG(p_journal_.warn())
2989 <<
"getNodeFat( " << *mn <<
") throws exception: " << info;
2993 JLOG(p_journal_.info())
2994 <<
"Got request for " << packet.nodeids().size() <<
" nodes at depth "
2995 << depth <<
", return " << reply.nodes().size() <<
" nodes";
2997 auto oPacket = std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
3002 PeerImp::getScore(
bool haveItem)
const
3006 static const int spRandomMax = 9999;
3010 static const int spHaveItem = 10000;
3015 static const int spLatency = 30;
3018 static const int spNoLatency = 8000;
3023 score += spHaveItem;
3025 boost::optional<std::chrono::milliseconds> latency;
3032 score -= latency->count() * spLatency;
3034 score -= spNoLatency;
3040 PeerImp::isHighLatency()
const
3043 return latency_ >= peerHighLatency;
3047 PeerImp::reduceRelayReady()
3049 if (!reduceRelayReady_)
3051 reduce_relay::epoch<std::chrono::minutes>(UptimeClock::now()) >
3052 reduce_relay::WAIT_ON_BOOTUP;
3053 return vpReduceRelayEnabled_ && reduceRelayReady_;
3059 using namespace std::chrono_literals;
3062 totalBytes_ += bytes;
3063 accumBytes_ += bytes;
3064 auto const timeElapsed = clock_type::now() - intervalStart_;
3065 auto const timeElapsedInSecs =
3066 std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
3068 if (timeElapsedInSecs >= 1s)
3070 auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
3071 rollingAvg_.push_back(avgBytes);
3073 auto const totalBytes =
3075 rollingAvgBytes_ = totalBytes / rollingAvg_.size();
3077 intervalStart_ = clock_type::now();
3083 PeerImp::Metrics::average_bytes()
const
3086 return rollingAvgBytes_;
3090 PeerImp::Metrics::total_bytes()
const