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>
53 using namespace std::chrono_literals;
70 , sink_(app_.journal(
"Peer"), makePrefix(id))
71 , p_sink_(app_.journal(
"Protocol"), makePrefix(id))
74 , stream_ptr_(
std::move(stream_ptr))
75 , socket_(stream_ptr_->next_layer().socket())
76 , stream_(*stream_ptr_)
77 , strand_(socket_.get_executor())
79 , remote_address_(slot->remote_endpoint())
83 , state_(State::active)
84 , sanity_(Sanity::unknown)
85 , insaneTime_(clock_type::now())
86 , publicKey_(publicKey)
87 , creationTime_(clock_type::now())
91 , request_(std::move(request))
93 , compressionEnabled_(
94 headers_[
"X-Offer-Compression"] ==
"lz4" ? Compressed::On
101 const bool inCluster{
cluster()};
124 if (!
strand_.running_in_this_thread())
128 auto parseLedgerHash =
129 [](
std::string const& value) -> boost::optional<uint256> {
140 boost::optional<uint256> closed;
141 boost::optional<uint256> previous;
143 if (
auto const iter =
headers_.find(
"Closed-Ledger");
146 closed = parseLedgerHash(iter->value().to_string());
149 fail(
"Malformed handshake data (1)");
152 if (
auto const iter =
headers_.find(
"Previous-Ledger");
155 previous = parseLedgerHash(iter->value().to_string());
158 fail(
"Malformed handshake data (2)");
161 if (previous && !closed)
162 fail(
"Malformed handshake data (3)");
186 protocol::TMGetPeerShardInfo tmGPS;
188 send(std::make_shared<Message>(tmGPS, protocol::mtGET_PEER_SHARD_INFO));
196 if (!
strand_.running_in_this_thread())
222 if (!
strand_.running_in_this_thread())
230 safe_cast<TrafficCount::category>(m->getCategory()),
250 <<
" sendq: " << sendq_size;
258 boost::asio::async_write(
267 std::placeholders::_1,
268 std::placeholders::_2)));
275 strand_.running_in_this_thread())
279 fail(
"charge: Resources");
288 auto const iter =
headers_.find(
"Crawl");
291 return boost::iequals(iter->value(),
"public");
304 return headers_[
"User-Agent"].to_string();
305 return headers_[
"Server"].to_string();
317 ret[jss::inbound] =
true;
321 ret[jss::cluster] =
true;
326 ret[jss::name] = name;
333 if (!version.empty())
334 ret[jss::version] = version;
346 std::chrono::duration_cast<std::chrono::seconds>(
uptime()).count());
351 if ((minSeq != 0) || (maxSeq != 0))
352 ret[jss::complete_ledgers] =
358 ret[jss::sanity] =
"insane";
362 ret[jss::sanity] =
"unknown";
371 protocol::TMStatusChange last_status;
378 if (closedLedgerHash != beast::zero)
379 ret[jss::ledger] =
to_string(closedLedgerHash);
381 if (last_status.has_newstatus())
383 switch (last_status.newstatus())
385 case protocol::nsCONNECTING:
386 ret[jss::status] =
"connecting";
389 case protocol::nsCONNECTED:
390 ret[jss::status] =
"connected";
393 case protocol::nsMONITORING:
394 ret[jss::status] =
"monitoring";
397 case protocol::nsVALIDATING:
398 ret[jss::status] =
"validating";
401 case protocol::nsSHUTTING:
402 ret[jss::status] =
"shutting";
407 <<
"Unknown status: " << last_status.newstatus();
412 ret[jss::metrics][jss::total_bytes_recv] =
414 ret[jss::metrics][jss::total_bytes_sent] =
416 ret[jss::metrics][jss::avg_bps_recv] =
418 ret[jss::metrics][jss::avg_bps_sent] =
469 return boost::icl::contains(it->second.shardIndexes, shardIndex);
504 assert(
strand_.running_in_this_thread());
526 if (!
strand_.running_in_this_thread())
538 <<
" failed: " << reason;
546 assert(
strand_.running_in_this_thread());
556 boost::optional<RangeSet<std::uint32_t>>
562 return it->second.shardIndexes;
566 boost::optional<hash_map<PublicKey, PeerImp::ShardInfo>>
578 assert(
strand_.running_in_this_thread());
590 stream_.async_shutdown(bind_executor(
607 timer_.async_wait(bind_executor(
637 if (ec == boost::asio::error::operation_aborted)
649 fail(
"Large send queue");
653 bool failedNoPing{
false};
654 boost::optional<std::uint32_t> pingSeq;
673 auto const minLatency =
674 std::chrono::duration_cast<std::chrono::milliseconds>(
684 fail(
"No ping reply received");
690 protocol::TMPing message;
691 message.set_type(protocol::TMPing::ptPING);
692 message.set_seq(*pingSeq);
694 send(std::make_shared<Message>(message, protocol::mtPING));
707 JLOG(
journal_.
error()) <<
"onShutdown: expected error condition";
710 if (ec != boost::asio::error::eof)
711 return fail(
"onShutdown", ec);
729 return fail(
"makeSharedValue: Unexpected failure");
769 resp.result(boost::beast::http::status::switching_protocols);
770 resp.version(req.version());
771 resp.insert(
"Connection",
"Upgrade");
773 resp.insert(
"Connect-As",
"Peer");
775 resp.insert(
"Crawl",
crawl ?
"public" :
"private");
777 resp.insert(
"X-Offer-Compression",
"lz4");
796 if (ec == boost::asio::error::operation_aborted)
799 return fail(
"onWriteResponse", ec);
802 if (bytes_transferred > 0)
803 stream <<
"onWriteResponse: " << bytes_transferred <<
" bytes";
805 stream <<
"onWriteResponse";
819 std::placeholders::_1,
820 std::placeholders::_2)));
849 protocol::TMValidatorList vl;
853 vl.set_signature(signature);
854 vl.set_version(version);
857 <<
"Sending validator list for " <<
strHex(pubKey)
858 <<
" with sequence " << sequence <<
" to "
860 auto m = std::make_shared<Message>(vl, protocol::mtVALIDATORLIST);
868 protocol::TMManifests tm;
871 [&tm](
std::size_t s) { tm.mutable_list()->Reserve(s); },
873 auto const& s =
manifest.serialized;
874 auto& tm_e = *tm.add_list();
875 tm_e.set_stobject(s.data(), s.size());
879 if (tm.list_size() > 0)
881 auto m = std::make_shared<Message>(tm, protocol::mtMANIFESTS);
892 if (ec == boost::asio::error::operation_aborted)
894 if (ec == boost::asio::error::eof)
900 return fail(
"onReadMessage", ec);
903 if (bytes_transferred > 0)
904 stream <<
"onReadMessage: " << bytes_transferred <<
" bytes";
906 stream <<
"onReadMessage";
909 metrics_.recv.add_message(bytes_transferred);
919 return fail(
"onReadMessage", ec);
924 if (bytes_consumed == 0)
936 std::placeholders::_1,
937 std::placeholders::_2)));
945 if (ec == boost::asio::error::operation_aborted)
948 return fail(
"onWriteMessage", ec);
951 if (bytes_transferred > 0)
952 stream <<
"onWriteMessage: " << bytes_transferred <<
" bytes";
954 stream <<
"onWriteMessage";
957 metrics_.sent.add_message(bytes_transferred);
964 return boost::asio::async_write(
973 std::placeholders::_1,
974 std::placeholders::_2)));
979 return stream_.async_shutdown(bind_executor(
984 std::placeholders::_1)));
1036 if (m->type() == protocol::TMPing::ptPING)
1040 m->set_type(protocol::TMPing::ptPONG);
1041 send(std::make_shared<Message>(*m, protocol::mtPING));
1045 if (m->type() == protocol::TMPing::ptPONG)
1061 auto const estimate =
1062 std::chrono::duration_cast<std::chrono::milliseconds>(
1086 for (
int i = 0; i < m->clusternodes().size(); ++i)
1088 protocol::TMClusterNode
const& node = m->clusternodes(i);
1091 if (node.has_nodename())
1092 name = node.nodename();
1094 auto const publicKey =
1101 auto const reportTime =
1105 *publicKey, name, node.nodeload(), reportTime);
1109 int loadSources = m->loadsources().size();
1110 if (loadSources != 0)
1113 gossip.
items.reserve(loadSources);
1114 for (
int i = 0; i < m->loadsources().size(); ++i)
1116 protocol::TMLoadSource
const& node = m->loadsources(i);
1121 gossip.
items.push_back(item);
1134 if (status.getReportTime() >= thresh)
1135 fees.push_back(status.getLoadFee());
1140 auto const index = fees.size() / 2;
1142 clusterFee = fees[index];
1171 return badData(
"Invalid peer chain");
1177 auto shards{shardStore->getCompleteShards()};
1178 if (!shards.empty())
1180 protocol::TMPeerShardInfo reply;
1181 reply.set_shardindexes(shards);
1183 if (m->has_lastlink())
1184 reply.set_lastlink(
true);
1186 if (m->peerchain_size() > 0)
1188 for (
int i = 0; i < m->peerchain_size(); ++i)
1191 return badData(
"Invalid peer chain public key");
1194 *reply.mutable_peerchain() = m->peerchain();
1197 send(std::make_shared<Message>(reply, protocol::mtPEER_SHARD_INFO));
1208 m->set_hops(m->hops() - 1);
1210 m->set_lastlink(
true);
1212 m->add_peerchain()->set_nodepubkey(
1216 std::make_shared<Message>(*m, protocol::mtGET_PEER_SHARD_INFO),
1229 if (m->shardindexes().empty())
1230 return badData(
"Missing shard indexes");
1232 return badData(
"Invalid peer chain");
1234 return badData(
"Invalid public key");
1237 if (m->peerchain_size() > 0)
1241 makeSlice(m->peerchain(m->peerchain_size() - 1).nodepubkey())};
1243 return badData(
"Invalid pubKey");
1248 if (!m->has_nodepubkey())
1251 if (!m->has_endpoint())
1257 m->set_endpoint(
"0");
1260 m->mutable_peerchain()->RemoveLast();
1262 std::make_shared<Message>(*m, protocol::mtPEER_SHARD_INFO));
1265 <<
"Relayed TMPeerShardInfo to peer with IP "
1280 if (!
from_string(shardIndexes, m->shardindexes()))
1281 return badData(
"Invalid shard indexes");
1284 boost::optional<std::uint32_t> latestShard;
1286 auto const curLedgerSeq{
1290 earliestShard = shardStore->earliestShardIndex();
1291 if (curLedgerSeq >= shardStore->earliestLedgerSeq())
1292 latestShard = shardStore->seqToShardIndex(curLedgerSeq);
1296 auto const earliestLedgerSeq{
1299 if (curLedgerSeq >= earliestLedgerSeq)
1304 if (boost::icl::first(shardIndexes) < earliestShard ||
1305 (latestShard && boost::icl::last(shardIndexes) > latestShard))
1307 return badData(
"Invalid shard indexes");
1313 if (m->has_endpoint())
1315 if (m->endpoint() !=
"0")
1320 return badData(
"Invalid incoming endpoint: " + m->endpoint());
1321 endpoint = std::move(*result);
1331 if (m->has_nodepubkey())
1342 it->second.endpoint = std::move(endpoint);
1345 it->second.shardIndexes += shardIndexes;
1351 shardInfo.
endpoint = std::move(endpoint);
1353 shardInfo_.emplace(publicKey, std::move(shardInfo));
1358 <<
"Consumed TMPeerShardInfo originating from public key "
1360 << m->shardindexes();
1362 if (m->has_lastlink())
1377 if (m->endpoints_v2().size())
1379 endpoints.
reserve(m->endpoints_v2().size());
1380 for (
auto const& tm : m->endpoints_v2())
1388 <<
"failed to parse incoming endpoint: {" << tm.endpoint()
1401 tm.hops() > 0 ? *result
1405 <<
"got v2 EP: " << endpoints.
back().address
1406 <<
", hops = " << endpoints.
back().hops;
1413 endpoints.
reserve(m->endpoints().size());
1414 for (
int i = 0; i < m->endpoints().size(); ++i)
1417 protocol::TMEndpoint
const& tm(m->endpoints(i));
1420 endpoint.
hops = tm.hops();
1423 if (endpoint.
hops > 0)
1426 addr.s_addr = tm.ipv4().ipv4();
1444 <<
"got v1 EP: " << endpoints.
back().address
1445 <<
", hops = " << endpoints.
back().hops;
1449 if (!endpoints.
empty())
1464 <<
"Need network ledger";
1472 auto stx = std::make_shared<STTx const>(sit);
1473 uint256 txID = stx->getTransactionID();
1492 bool checkSignature =
true;
1495 if (!m->has_deferred() || !m->deferred())
1499 flags |= SF_TRUSTED;
1506 checkSignature =
false;
1511 constexpr
int max_transactions = 250;
1520 <<
"No new transactions until synchronized";
1526 "recvTransaction->checkTransaction",
1531 if (
auto peer = weak.lock())
1532 peer->checkTransaction(flags, checkSignature, stx);
1539 <<
"Transaction invalid: " <<
strHex(m->rawtransaction());
1549 if (
auto peer = weak.
lock())
1557 protocol::TMLedgerData& packet = *m;
1559 if (m->nodes().size() <= 0)
1565 if (m->has_requestcookie())
1571 m->clear_requestcookie();
1573 std::make_shared<Message>(packet, protocol::mtLEDGER_DATA));
1577 JLOG(
p_journal_.
info()) <<
"Unable to route TX/ledger data reply";
1585 JLOG(
p_journal_.
warn()) <<
"TX candidate reply with invalid hash size";
1590 uint256 const hash{m->ledgerhash()};
1592 if (m->type() == protocol::liTS_CANDIDATE)
1598 if (
auto peer = weak.
lock())
1599 peer->app_.getInboundTransactions().gotData(hash, peer, m);
1614 protocol::TMProposeSet&
set = *m;
1620 if ((boost::algorithm::clamp(sig.size(), 64, 72) != sig.size()) ||
1636 uint256 const proposeHash{
set.currenttxhash()};
1637 uint256 const prevLedger{
set.previousledger()};
1674 <<
"Proposal: " << (isTrusted ?
"trusted" :
"UNTRUSTED");
1691 "recvPropose->checkPropose",
1693 if (
auto peer = weak.lock())
1694 peer->checkPropose(job, m,
proposal);
1703 if (!m->has_networktime())
1708 if (!
last_status_.has_newstatus() || m->has_newstatus())
1713 protocol::NodeStatus status =
last_status_.newstatus();
1715 m->set_newstatus(status);
1719 if (m->newevent() == protocol::neLOST_SYNC)
1721 bool outOfSync{
false};
1742 bool const peerChangedLedgers{
1749 if (peerChangedLedgers)
1760 if (m->has_ledgerhashprevious() &&
1771 if (peerChangedLedgers)
1781 if (m->has_firstseq() && m->has_lastseq())
1792 if (m->has_ledgerseq() &&
1802 if (m->has_newstatus())
1804 switch (m->newstatus())
1806 case protocol::nsCONNECTING:
1807 j[jss::status] =
"CONNECTING";
1809 case protocol::nsCONNECTED:
1810 j[jss::status] =
"CONNECTED";
1812 case protocol::nsMONITORING:
1813 j[jss::status] =
"MONITORING";
1815 case protocol::nsVALIDATING:
1816 j[jss::status] =
"VALIDATING";
1818 case protocol::nsSHUTTING:
1819 j[jss::status] =
"SHUTTING";
1824 if (m->has_newevent())
1826 switch (m->newevent())
1828 case protocol::neCLOSING_LEDGER:
1829 j[jss::action] =
"CLOSING_LEDGER";
1831 case protocol::neACCEPTED_LEDGER:
1832 j[jss::action] =
"ACCEPTED_LEDGER";
1834 case protocol::neSWITCHED_LEDGER:
1835 j[jss::action] =
"SWITCHED_LEDGER";
1837 case protocol::neLOST_SYNC:
1838 j[jss::action] =
"LOST_SYNC";
1843 if (m->has_ledgerseq())
1845 j[jss::ledger_index] = m->ledgerseq();
1848 if (m->has_ledgerhash())
1850 uint256 closedLedgerHash{};
1852 std::lock_guard sl(recentLock_);
1853 closedLedgerHash = closedLedgerHash_;
1855 j[jss::ledger_hash] =
to_string(closedLedgerHash);
1858 if (m->has_networktime())
1860 j[jss::date] = Json::UInt(m->networktime());
1863 if (m->has_firstseq() && m->has_lastseq())
1865 j[jss::ledger_index_min] = Json::UInt(m->firstseq());
1866 j[jss::ledger_index_max] = Json::UInt(m->lastseq());
1882 serverSeq = maxLedger_;
1888 checkSanity(serverSeq, validationSeq);
1897 if (
diff < Tuning::saneLedgerLimit)
1900 sanity_ = Sanity::sane;
1903 if ((
diff > Tuning::insaneLedgerLimit) &&
1904 (sanity_.load() != Sanity::insane))
1909 sanity_ = Sanity::insane;
1910 insaneTime_ = clock_type::now();
1919 if (m_inbound || (sanity_.load() == Sanity::sane))
1922 clock_type::time_point insaneTime;
1926 insaneTime = insaneTime_;
1929 bool reject =
false;
1931 if (sanity_.load() == Sanity::insane)
1932 reject = (insaneTime - clock_type::now()) >
1935 if (sanity_.load() == Sanity::unknown)
1936 reject = (insaneTime - clock_type::now()) >
1941 overlay_.peerFinder().on_failure(slot_);
1956 fee_ = Resource::feeInvalidRequest;
1960 uint256 const hash{m->hash()};
1962 if (m->status() == protocol::tsHAVE)
1966 if (
std::find(recentTxSets_.begin(), recentTxSets_.end(), hash) !=
1967 recentTxSets_.end())
1969 fee_ = Resource::feeUnwantedData;
1973 recentTxSets_.push_back(hash);
1982 if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
1984 JLOG(p_journal_.debug())
1985 <<
"ValidatorList: received validator list from peer using "
1986 <<
"protocol version " << to_string(protocol_)
1987 <<
" which shouldn't support this feature.";
1988 fee_ = Resource::feeUnwantedData;
1991 auto const&
manifest = m->manifest();
1992 auto const& blob = m->blob();
1993 auto const& signature = m->signature();
1994 auto const version = m->version();
1997 JLOG(p_journal_.debug())
1998 <<
"Received validator list from " << remote_address_.to_string()
1999 <<
" (" << id_ <<
")";
2001 if (!app_.getHashRouter().addSuppressionPeer(hash, id_))
2003 JLOG(p_journal_.debug())
2004 <<
"ValidatorList: received duplicate validator list";
2008 fee_ = Resource::feeUnwantedData;
2012 auto const applyResult = app_.validators().applyListAndBroadcast(
2017 remote_address_.to_string(),
2020 app_.getHashRouter());
2021 auto const disp = applyResult.disposition;
2023 JLOG(p_journal_.debug())
2024 <<
"Processed validator list from "
2025 << (applyResult.publisherKey ?
strHex(*applyResult.publisherKey)
2026 :
"unknown or invalid publisher")
2027 <<
" from " << remote_address_.to_string() <<
" (" << id_
2028 <<
") with result " << to_string(disp);
2032 case ListDisposition::accepted:
2033 JLOG(p_journal_.debug())
2034 <<
"Applied new validator list from peer "
2039 assert(applyResult.sequence && applyResult.publisherKey);
2040 auto const& pubKey = *applyResult.publisherKey;
2042 if (
auto const iter = publisherListSequences_.find(pubKey);
2043 iter != publisherListSequences_.end())
2045 assert(iter->second < *applyResult.sequence);
2048 publisherListSequences_[pubKey] = *applyResult.sequence;
2051 case ListDisposition::same_sequence:
2052 JLOG(p_journal_.warn())
2053 <<
"Validator list with current sequence from peer "
2058 fee_ = Resource::feeUnwantedData;
2062 assert(applyResult.sequence && applyResult.publisherKey);
2064 publisherListSequences_[*applyResult.publisherKey] ==
2065 *applyResult.sequence);
2070 case ListDisposition::stale:
2071 JLOG(p_journal_.warn())
2072 <<
"Stale validator list from peer " << remote_address_;
2075 fee_ = Resource::feeBadData;
2077 case ListDisposition::untrusted:
2078 JLOG(p_journal_.warn())
2079 <<
"Untrusted validator list from peer " << remote_address_;
2083 fee_ = Resource::feeUnwantedData;
2085 case ListDisposition::invalid:
2086 JLOG(p_journal_.warn())
2087 <<
"Invalid validator list from peer " << remote_address_;
2089 fee_ = Resource::feeInvalidSignature;
2091 case ListDisposition::unsupported_version:
2092 JLOG(p_journal_.warn())
2093 <<
"Unsupported version validator list from peer "
2097 fee_ = Resource::feeBadData;
2105 JLOG(p_journal_.warn()) <<
"ValidatorList: Exception, " << e.
what()
2106 <<
" from peer " << remote_address_;
2107 fee_ = Resource::feeBadData;
2114 auto const closeTime = app_.timeKeeper().closeTime();
2116 if (m->validation().size() < 50)
2118 JLOG(p_journal_.warn()) <<
"Validation: Too small";
2119 fee_ = Resource::feeInvalidRequest;
2128 val = std::make_shared<STValidation>(
2132 app_.validatorManifests().getMasterKey(pk));
2135 val->setSeen(closeTime);
2139 app_.getValidations().parms(),
2140 app_.timeKeeper().closeTime(),
2142 val->getSeenTime()))
2144 JLOG(p_journal_.trace()) <<
"Validation: Not current";
2145 fee_ = Resource::feeUnwantedData;
2149 if (!app_.getHashRouter().addSuppressionPeer(
2152 JLOG(p_journal_.trace()) <<
"Validation: duplicate";
2156 auto const isTrusted =
2157 app_.validators().trusted(val->getSignerPublic());
2159 if (!isTrusted && (sanity_.load() == Sanity::insane))
2161 JLOG(p_journal_.debug())
2162 <<
"Validation: dropping untrusted from insane peer";
2164 if (isTrusted || cluster() || !app_.getFeeTrack().isLoadedLocal())
2167 app_.getJobQueue().addJob(
2169 "recvValidation->checkValidation",
2170 [weak, val, m](
Job&) {
2171 if (
auto peer = weak.
lock())
2172 peer->checkValidation(val, m);
2177 JLOG(p_journal_.debug()) <<
"Validation: Dropping UNTRUSTED (load)";
2182 JLOG(p_journal_.warn())
2183 <<
"Exception processing validation: " << e.
what();
2184 fee_ = Resource::feeInvalidRequest;
2191 protocol::TMGetObjectByHash& packet = *m;
2196 if (send_queue_.size() >= Tuning::dropSendQueue)
2198 JLOG(p_journal_.debug()) <<
"GetObject: Large send queue";
2202 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2208 fee_ = Resource::feeMediumBurdenPeer;
2210 protocol::TMGetObjectByHash reply;
2212 reply.set_query(
false);
2214 if (packet.has_seq())
2215 reply.set_seq(packet.seq());
2217 reply.set_type(packet.type());
2219 if (packet.has_ledgerhash())
2223 fee_ = Resource::feeInvalidRequest;
2227 reply.set_ledgerhash(packet.ledgerhash());
2231 for (
int i = 0; i < packet.objects_size(); ++i)
2233 auto const& obj = packet.objects(i);
2236 uint256 const hash{obj.hash()};
2239 std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2240 auto hObj{app_.getNodeStore().fetch(hash, seq)};
2243 if (
auto shardStore = app_.getShardStore())
2245 if (seq >= shardStore->earliestLedgerSeq())
2246 hObj = shardStore->fetch(hash, seq);
2251 protocol::TMIndexedObject& newObj = *reply.add_objects();
2252 newObj.set_hash(hash.begin(), hash.size());
2254 &hObj->getData().front(), hObj->getData().size());
2256 if (obj.has_nodeid())
2257 newObj.set_index(obj.nodeid());
2258 if (obj.has_ledgerseq())
2259 newObj.set_ledgerseq(obj.ledgerseq());
2266 JLOG(p_journal_.trace()) <<
"GetObj: " << reply.objects_size() <<
" of "
2267 << packet.objects_size();
2268 send(std::make_shared<Message>(reply, protocol::mtGET_OBJECTS));
2275 bool progress =
false;
2277 for (
int i = 0; i < packet.objects_size(); ++i)
2279 const protocol::TMIndexedObject& obj = packet.objects(i);
2283 if (obj.has_ledgerseq())
2285 if (obj.ledgerseq() != pLSeq)
2287 if (pLDo && (pLSeq != 0))
2289 JLOG(p_journal_.debug())
2290 <<
"GetObj: Full fetch pack for " << pLSeq;
2292 pLSeq = obj.ledgerseq();
2293 pLDo = !app_.getLedgerMaster().haveLedger(pLSeq);
2297 JLOG(p_journal_.debug())
2298 <<
"GetObj: Late fetch pack for " << pLSeq;
2307 uint256 const hash{obj.hash()};
2309 app_.getLedgerMaster().addFetchPack(
2311 std::make_shared<Blob>(
2312 obj.data().begin(), obj.data().end()));
2317 if (pLDo && (pLSeq != 0))
2319 JLOG(p_journal_.debug())
2320 <<
"GetObj: Partial fetch pack for " << pLSeq;
2322 if (packet.type() == protocol::TMGetObjectByHash::otFETCH_PACK)
2323 app_.getLedgerMaster().gotFetchPack(progress, pLSeq);
2336 (void)lockedRecentLock;
2338 if (
std::find(recentLedgers_.begin(), recentLedgers_.end(), hash) !=
2339 recentLedgers_.end())
2342 recentLedgers_.push_back(hash);
2351 if (app_.getFeeTrack().isLoadedLocal() ||
2352 (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2353 (app_.getJobQueue().getJobCount(
jtPACK) > 10))
2355 JLOG(p_journal_.info()) <<
"Too busy to make fetch pack";
2361 JLOG(p_journal_.warn()) <<
"FetchPack hash size malformed";
2362 fee_ = Resource::feeInvalidRequest;
2366 fee_ = Resource::feeHighBurdenPeer;
2368 uint256 const hash{packet->ledgerhash()};
2371 auto elapsed = UptimeClock::now();
2372 auto const pap = &app_;
2373 app_.getJobQueue().addJob(
2374 jtPACK,
"MakeFetchPack", [pap, weak, packet, hash, elapsed](
Job&) {
2375 pap->getLedgerMaster().makeFetchPack(weak, packet, hash, elapsed);
2380 PeerImp::checkTransaction(
2382 bool checkSignature,
2391 app_.getLedgerMaster().getValidLedgerIndex()))
2393 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2394 charge(Resource::feeUnwantedData);
2402 app_.getHashRouter(),
2404 app_.getLedgerMaster().getValidatedRules(),
2406 valid != Validity::Valid)
2408 if (!validReason.empty())
2410 JLOG(p_journal_.trace())
2411 <<
"Exception checking transaction: " << validReason;
2415 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2416 charge(Resource::feeInvalidSignature);
2423 app_.getHashRouter(), stx->getTransactionID(), Validity::Valid);
2427 auto tx = std::make_shared<Transaction>(stx, reason, app_);
2429 if (tx->getStatus() ==
INVALID)
2431 if (!reason.
empty())
2433 JLOG(p_journal_.trace())
2434 <<
"Exception checking transaction: " << reason;
2436 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2437 charge(Resource::feeInvalidSignature);
2441 bool const trusted(flags & SF_TRUSTED);
2442 app_.getOPs().processTransaction(
2443 tx, trusted,
false, NetworkOPs::FailHard::no);
2447 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2448 charge(Resource::feeBadData);
2454 PeerImp::checkPropose(
2461 JLOG(p_journal_.trace())
2462 <<
"Checking " << (isTrusted ?
"trusted" :
"UNTRUSTED") <<
" proposal";
2468 JLOG(p_journal_.warn()) <<
"Proposal fails sig check";
2469 charge(Resource::feeInvalidSignature);
2476 relay = app_.getOPs().processTrustedProposal(peerPos);
2478 relay = app_.config().RELAY_UNTRUSTED_PROPOSALS || cluster();
2485 PeerImp::checkValidation(
2492 if (!cluster() && !val->isValid())
2494 JLOG(p_journal_.warn()) <<
"Validation is invalid";
2495 charge(Resource::feeInvalidRequest);
2502 auto const suppression =
2504 overlay_.relay(*packet, suppression);
2509 JLOG(p_journal_.trace()) <<
"Exception processing validation";
2510 charge(Resource::feeInvalidRequest);
2524 if (p->hasTxSet(rootHash) && p.get() != skip)
2526 auto score = p->getScore(true);
2527 if (!ret || (score > retScore))
2552 if (p->hasLedger(ledgerHash, ledger) && p.get() != skip)
2554 auto score = p->getScore(true);
2555 if (!ret || (score > retScore))
2570 protocol::TMGetLedger& packet = *m;
2572 SHAMap const* map =
nullptr;
2573 protocol::TMLedgerData reply;
2574 bool fatLeaves =
true;
2577 if (packet.has_requestcookie())
2578 reply.set_requestcookie(packet.requestcookie());
2582 if (packet.itype() == protocol::liTS_CANDIDATE)
2585 JLOG(p_journal_.trace()) <<
"GetLedger: Tx candidate set";
2587 if (!packet.has_ledgerhash() ||
2590 charge(Resource::feeInvalidRequest);
2591 JLOG(p_journal_.warn()) <<
"GetLedger: Tx candidate set invalid";
2595 uint256 const txHash{packet.ledgerhash()};
2597 shared = app_.getInboundTransactions().getSet(txHash,
false);
2602 if (packet.has_querytype() && !packet.has_requestcookie())
2604 JLOG(p_journal_.debug()) <<
"GetLedger: Routing Tx set request";
2608 packet.set_requestcookie(
id());
2609 v->send(std::make_shared<Message>(
2610 packet, protocol::mtGET_LEDGER));
2614 JLOG(p_journal_.info()) <<
"GetLedger: Route TX set failed";
2618 JLOG(p_journal_.debug()) <<
"GetLedger: Can't provide map ";
2619 charge(Resource::feeInvalidRequest);
2623 reply.set_ledgerseq(0);
2624 reply.set_ledgerhash(txHash.begin(), txHash.size());
2625 reply.set_type(protocol::liTS_CANDIDATE);
2630 if (send_queue_.size() >= Tuning::dropSendQueue)
2632 JLOG(p_journal_.debug()) <<
"GetLedger: Large send queue";
2636 if (app_.getFeeTrack().isLoadedLocal() && !cluster())
2638 JLOG(p_journal_.debug()) <<
"GetLedger: Too busy";
2643 JLOG(p_journal_.trace()) <<
"GetLedger: Received";
2645 if (packet.has_ledgerhash())
2649 charge(Resource::feeInvalidRequest);
2650 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid request";
2654 uint256 const ledgerhash{packet.ledgerhash()};
2655 logMe +=
"LedgerHash:";
2656 logMe += to_string(ledgerhash);
2657 ledger = app_.getLedgerMaster().getLedgerByHash(ledgerhash);
2659 if (!ledger && packet.has_ledgerseq())
2661 if (
auto shardStore = app_.getShardStore())
2663 auto seq = packet.ledgerseq();
2664 if (seq >= shardStore->earliestLedgerSeq())
2665 ledger = shardStore->fetchLedger(ledgerhash, seq);
2671 JLOG(p_journal_.trace())
2672 <<
"GetLedger: Don't have " << ledgerhash;
2676 (packet.has_querytype() && !packet.has_requestcookie()))
2683 packet.has_ledgerseq() ? packet.ledgerseq() : 0,
2687 JLOG(p_journal_.trace()) <<
"GetLedger: Cannot route";
2691 packet.set_requestcookie(
id());
2693 std::make_shared<Message>(packet, protocol::mtGET_LEDGER));
2694 JLOG(p_journal_.debug()) <<
"GetLedger: Request routed";
2698 else if (packet.has_ledgerseq())
2700 if (packet.ledgerseq() < app_.getLedgerMaster().getEarliestFetch())
2702 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2705 ledger = app_.getLedgerMaster().getLedgerBySeq(packet.ledgerseq());
2708 JLOG(p_journal_.debug())
2709 <<
"GetLedger: Don't have " << packet.ledgerseq();
2712 else if (packet.has_ltype() && (packet.ltype() == protocol::ltCLOSED))
2714 ledger = app_.getLedgerMaster().getClosedLedger();
2715 assert(!ledger->open());
2719 if (ledger && ledger->info().open)
2720 ledger = app_.getLedgerMaster ().getLedgerBySeq (
2721 ledger->info().seq - 1);
2726 charge(Resource::feeInvalidRequest);
2727 JLOG(p_journal_.warn()) <<
"GetLedger: Unknown request";
2732 (packet.has_ledgerseq() &&
2733 (packet.ledgerseq() != ledger->info().seq)))
2735 charge(Resource::feeInvalidRequest);
2739 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid sequence";
2744 if (!packet.has_ledgerseq() &&
2745 (ledger->info().seq < app_.getLedgerMaster().getEarliestFetch()))
2747 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2752 auto const lHash = ledger->info().hash;
2753 reply.set_ledgerhash(lHash.begin(), lHash.size());
2754 reply.set_ledgerseq(ledger->info().seq);
2755 reply.set_type(packet.itype());
2757 if (packet.itype() == protocol::liBASE)
2760 JLOG(p_journal_.trace()) <<
"GetLedger: Base data";
2762 addRaw(ledger->info(), nData);
2763 reply.add_nodes()->set_nodedata(
2766 auto const& stateMap = ledger->stateMap();
2767 if (stateMap.getHash() != beast::zero)
2771 if (stateMap.getRootNode(rootNode,
snfWIRE))
2773 reply.add_nodes()->set_nodedata(
2776 if (ledger->info().txHash != beast::zero)
2778 auto const& txMap = ledger->txMap();
2780 if (txMap.getHash() != beast::zero)
2784 if (txMap.getRootNode(rootNode,
snfWIRE))
2785 reply.add_nodes()->set_nodedata(
2794 std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
2799 if (packet.itype() == protocol::liTX_NODE)
2801 map = &ledger->txMap();
2803 logMe += to_string(map->
getHash());
2805 else if (packet.itype() == protocol::liAS_NODE)
2807 map = &ledger->stateMap();
2809 logMe += to_string(map->
getHash());
2813 if (!map || (packet.nodeids_size() == 0))
2815 JLOG(p_journal_.warn()) <<
"GetLedger: Can't find map or empty request";
2816 charge(Resource::feeInvalidRequest);
2820 JLOG(p_journal_.trace()) <<
"GetLedger: " << logMe;
2822 auto const depth = packet.has_querydepth()
2823 ? (
std::min(packet.querydepth(), 3u))
2824 : (isHighLatency() ? 2 : 1);
2827 (i < packet.nodeids().size() &&
2828 (reply.nodes().size() < Tuning::maxReplyNodes));
2831 SHAMapNodeID mn(packet.nodeids(i).data(), packet.nodeids(i).size());
2835 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid node " << logMe;
2836 charge(Resource::feeInvalidRequest);
2845 if (map->
getNodeFat(mn, nodeIDs, rawNodes, fatLeaves, depth))
2847 assert(nodeIDs.
size() == rawNodes.
size());
2848 JLOG(p_journal_.trace()) <<
"GetLedger: getNodeFat got "
2849 << rawNodes.
size() <<
" nodes";
2853 for (nodeIDIterator = nodeIDs.
begin(),
2854 rawNodeIterator = rawNodes.
begin();
2855 nodeIDIterator != nodeIDs.
end();
2856 ++nodeIDIterator, ++rawNodeIterator)
2859 nodeIDIterator->addIDRaw(nID);
2860 protocol::TMLedgerNode* node = reply.add_nodes();
2863 &rawNodeIterator->
front(), rawNodeIterator->
size());
2868 JLOG(p_journal_.warn())
2869 <<
"GetLedger: getNodeFat returns false";
2876 if (packet.itype() == protocol::liTS_CANDIDATE)
2877 info =
"TS candidate";
2878 else if (packet.itype() == protocol::liBASE)
2879 info =
"Ledger base";
2880 else if (packet.itype() == protocol::liTX_NODE)
2882 else if (packet.itype() == protocol::liAS_NODE)
2885 if (!packet.has_ledgerhash())
2886 info +=
", no hash specified";
2888 JLOG(p_journal_.warn())
2889 <<
"getNodeFat( " << mn <<
") throws exception: " << info;
2893 JLOG(p_journal_.info())
2894 <<
"Got request for " << packet.nodeids().size() <<
" nodes at depth "
2895 << depth <<
", return " << reply.nodes().size() <<
" nodes";
2897 auto oPacket = std::make_shared<Message>(reply, protocol::mtLEDGER_DATA);
2902 PeerImp::getScore(
bool haveItem)
const
2906 static const int spRandomMax = 9999;
2910 static const int spHaveItem = 10000;
2915 static const int spLatency = 30;
2918 static const int spNoLatency = 8000;
2923 score += spHaveItem;
2925 boost::optional<std::chrono::milliseconds> latency;
2932 score -= latency->count() * spLatency;
2934 score -= spNoLatency;
2940 PeerImp::isHighLatency()
const
2943 return latency_ >= Tuning::peerHighLatency;
2949 using namespace std::chrono_literals;
2952 totalBytes_ += bytes;
2953 accumBytes_ += bytes;
2954 auto const timeElapsed = clock_type::now() - intervalStart_;
2955 auto const timeElapsedInSecs =
2956 std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
2958 if (timeElapsedInSecs >= 1s)
2960 auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
2961 rollingAvg_.push_back(avgBytes);
2963 auto const totalBytes =
2965 rollingAvgBytes_ = totalBytes / rollingAvg_.size();
2967 intervalStart_ = clock_type::now();
2973 PeerImp::Metrics::average_bytes()
const
2976 return rollingAvgBytes_;
2980 PeerImp::Metrics::total_bytes()
const