20 #include <ripple/overlay/impl/PeerImp.h>
21 #include <ripple/overlay/impl/Tuning.h>
22 #include <ripple/app/consensus/RCLValidations.h>
23 #include <ripple/app/ledger/InboundLedgers.h>
24 #include <ripple/app/ledger/LedgerMaster.h>
25 #include <ripple/app/ledger/InboundTransactions.h>
26 #include <ripple/app/misc/HashRouter.h>
27 #include <ripple/app/misc/LoadFeeTrack.h>
28 #include <ripple/app/misc/NetworkOPs.h>
29 #include <ripple/app/misc/Transaction.h>
30 #include <ripple/app/misc/ValidatorList.h>
31 #include <ripple/app/tx/apply.h>
32 #include <ripple/basics/base64.h>
33 #include <ripple/basics/random.h>
34 #include <ripple/basics/safe_cast.h>
35 #include <ripple/basics/UptimeClock.h>
36 #include <ripple/beast/core/LexicalCast.h>
37 #include <ripple/beast/core/SemanticVersion.h>
38 #include <ripple/nodestore/DatabaseShard.h>
39 #include <ripple/overlay/Cluster.h>
40 #include <ripple/overlay/predicates.h>
41 #include <ripple/protocol/digest.h>
43 #include <boost/algorithm/clamp.hpp>
44 #include <boost/algorithm/string/predicate.hpp>
45 #include <boost/algorithm/string.hpp>
46 #include <boost/beast/core/ostream.hpp>
53 using namespace std::chrono_literals;
66 , sink_(app_.journal(
"Peer"), makePrefix(id))
67 , p_sink_(app_.journal(
"Protocol"), makePrefix(id))
70 , stream_ptr_(
std::move(stream_ptr))
71 , socket_ (stream_ptr_->next_layer().socket())
72 , stream_ (*stream_ptr_)
73 , strand_ (socket_.get_executor())
75 , remote_address_ (slot->remote_endpoint())
78 , protocol_ (protocol)
79 , state_ (State::active)
80 , sanity_ (Sanity::unknown)
81 , insaneTime_ (clock_type::now())
82 , publicKey_(publicKey)
83 , creationTime_ (clock_type::now())
87 , request_(std::move(request))
89 , compressionEnabled_(headers_[
"X-Offer-Compression"] ==
"lz4" ? Compressed::On : Compressed::Off)
95 const bool inCluster {
cluster()};
119 if(!
strand_.running_in_this_thread())
123 auto parseLedgerHash = [](
std::string const& value) -> boost::optional<uint256>
135 boost::optional<uint256> closed;
136 boost::optional<uint256> previous;
138 if (
auto const iter =
headers_.find(
"Closed-Ledger"); iter !=
headers_.end())
140 closed = parseLedgerHash(iter->value().to_string());
143 fail(
"Malformed handshake data (1)");
146 if (
auto const iter =
headers_.find(
"Previous-Ledger"); iter !=
headers_.end())
148 previous = parseLedgerHash(iter->value().to_string());
151 fail(
"Malformed handshake data (2)");
154 if (previous && !closed)
155 fail(
"Malformed handshake data (3)");
178 protocol::TMGetPeerShardInfo tmGPS;
180 send(std::make_shared<Message>(tmGPS, protocol::mtGET_PEER_SHARD_INFO));
188 if(!
strand_.running_in_this_thread())
214 if (!
strand_.running_in_this_thread())
222 safe_cast<TrafficCount::category>(m->getCategory()),
240 " sendq: " << sendq_size;
248 boost::asio::async_write(
256 std::placeholders::_1,
257 std::placeholders::_2)));
268 fail(
"charge: Resources");
277 auto const iter =
headers_.find(
"Crawl");
280 return boost::iequals(iter->value(),
"public");
293 return headers_[
"User-Agent"].to_string();
294 return headers_[
"Server"].to_string();
307 ret[jss::inbound] =
true;
311 ret[jss::cluster] =
true;
315 ret[jss::name] = std::move(name);
322 if (!version.empty())
323 ret[jss::version] = version;
335 std::chrono::duration_cast<std::chrono::seconds>(
uptime()).count());
340 if ((minSeq != 0) || (maxSeq != 0))
347 ret[jss::sanity] =
"insane";
351 ret[jss::sanity] =
"unknown";
360 protocol::TMStatusChange last_status;
367 if (closedLedgerHash != beast::zero)
368 ret[jss::ledger] =
to_string (closedLedgerHash);
370 if (last_status.has_newstatus ())
372 switch (last_status.newstatus ())
374 case protocol::nsCONNECTING:
375 ret[jss::status] =
"connecting";
378 case protocol::nsCONNECTED:
379 ret[jss::status] =
"connected";
382 case protocol::nsMONITORING:
383 ret[jss::status] =
"monitoring";
386 case protocol::nsVALIDATING:
387 ret[jss::status] =
"validating";
390 case protocol::nsSHUTTING:
391 ret[jss::status] =
"shutting";
396 "Unknown status: " << last_status.newstatus ();
455 return boost::icl::contains(it->second.shardIndexes, shardIndex);
491 assert(
strand_.running_in_this_thread());
513 if(!
strand_.running_in_this_thread())
525 " failed: " << reason;
533 assert(
strand_.running_in_this_thread());
539 ": " << ec.message();
544 boost::optional<RangeSet<std::uint32_t>>
550 return it->second.shardIndexes;
554 boost::optional<hash_map<PublicKey, PeerImp::ShardInfo>>
566 assert(
strand_.running_in_this_thread());
578 stream_.async_shutdown(bind_executor(
596 timer_.async_wait(bind_executor(
626 if (ec == boost::asio::error::operation_aborted)
638 fail (
"Large send queue");
642 bool failedNoPing {
false};
643 boost::optional<std::uint32_t> pingSeq;
662 auto const minLatency =
663 std::chrono::duration_cast<std::chrono::milliseconds>
673 fail (
"No ping reply received");
679 protocol::TMPing message;
680 message.set_type (protocol::TMPing::ptPING);
681 message.set_seq (*pingSeq);
683 send (std::make_shared<Message> (message, protocol::mtPING));
696 JLOG(
journal_.
error()) <<
"onShutdown: expected error condition";
699 if (ec != boost::asio::error::eof)
700 return fail(
"onShutdown", ec);
717 return fail(
"makeSharedValue: Unexpected failure");
754 resp.result(boost::beast::http::status::switching_protocols);
755 resp.version(req.version());
756 resp.insert(
"Connection",
"Upgrade");
758 resp.insert(
"Connect-As",
"Peer");
760 resp.insert(
"Crawl",
crawl ?
"public" :
"private");
762 resp.insert(
"X-Offer-Compression",
"lz4");
776 if(ec == boost::asio::error::operation_aborted)
779 return fail(
"onWriteResponse", ec);
782 if (bytes_transferred > 0)
784 "onWriteResponse: " << bytes_transferred <<
" bytes";
786 stream <<
"onWriteResponse";
800 std::placeholders::_1,
801 std::placeholders::_2)));
830 protocol::TMValidatorList vl;
834 vl.set_signature(signature);
835 vl.set_version(version);
838 strHex(pubKey) <<
" with sequence " <<
839 sequence <<
" to " <<
841 auto m = std::make_shared<Message>(vl, protocol::mtVALIDATORLIST);
850 protocol::TMManifests tm;
853 [&tm](
std::size_t s){tm.mutable_list()->Reserve(s);},
856 auto const& s =
manifest.serialized;
857 auto& tm_e = *tm.add_list();
858 tm_e.set_stobject(s.data(), s.size());
862 if (tm.list_size() > 0)
864 auto m = std::make_shared<Message>(tm, protocol::mtMANIFESTS);
875 if(ec == boost::asio::error::operation_aborted)
877 if(ec == boost::asio::error::eof)
883 return fail(
"onReadMessage", ec);
886 if (bytes_transferred > 0)
888 "onReadMessage: " << bytes_transferred <<
" bytes";
890 stream <<
"onReadMessage";
893 metrics_.recv.add_message(bytes_transferred);
903 return fail(
"onReadMessage", ec);
908 if (bytes_consumed == 0)
920 std::placeholders::_1,
921 std::placeholders::_2)));
929 if(ec == boost::asio::error::operation_aborted)
932 return fail(
"onWriteMessage", ec);
935 if (bytes_transferred > 0)
937 "onWriteMessage: " << bytes_transferred <<
" bytes";
939 stream <<
"onWriteMessage";
942 metrics_.sent.add_message(bytes_transferred);
949 return boost::asio::async_write(
957 std::placeholders::_1,
958 std::placeholders::_2)));
963 return stream_.async_shutdown(bind_executor(
968 std::placeholders::_1)));
993 true,
static_cast<int>(size));
1017 if (m->type () == protocol::TMPing::ptPING)
1021 m->set_type (protocol::TMPing::ptPONG);
1022 send (std::make_shared<Message> (*m, protocol::mtPING));
1026 if (m->type () == protocol::TMPing::ptPONG)
1042 auto const estimate =
1043 std::chrono::duration_cast<std::chrono::milliseconds>
1067 for (
int i = 0; i < m->clusternodes().size(); ++i)
1069 protocol::TMClusterNode
const& node = m->clusternodes(i);
1072 if (node.has_nodename())
1073 name = node.nodename();
1075 auto const publicKey = parseBase58<PublicKey>(
1082 auto const reportTime =
1094 int loadSources = m->loadsources().size();
1095 if (loadSources != 0)
1098 gossip.
items.reserve (loadSources);
1099 for (
int i = 0; i < m->loadsources().size(); ++i)
1101 protocol::TMLoadSource
const& node = m->loadsources (i);
1106 gossip.
items.push_back(item);
1121 if (status.getReportTime() >= thresh)
1127 auto const index = fees.
size() / 2;
1130 fees.
begin () + index,
1132 clusterFee = fees[index];
1161 return badData(
"Invalid peer chain");
1167 auto shards {shardStore->getCompleteShards()};
1168 if (!shards.empty())
1170 protocol::TMPeerShardInfo reply;
1171 reply.set_shardindexes(shards);
1173 if (m->has_lastlink())
1174 reply.set_lastlink(
true);
1176 if (m->peerchain_size() > 0)
1177 *reply.mutable_peerchain() = m->peerchain();
1179 send(std::make_shared<Message>(
1180 reply, protocol::mtPEER_SHARD_INFO));
1183 "Sent shard indexes " << shards;
1192 m->set_hops(m->hops() - 1);
1194 m->set_lastlink(
true);
1196 m->add_peerchain()->set_nodepubkey(
1200 std::make_shared<Message>(*m, protocol::mtGET_PEER_SHARD_INFO),
1213 if (m->shardindexes().empty())
1214 return badData(
"Missing shard indexes");
1216 return badData(
"Invalid peer chain");
1218 return badData(
"Invalid public key");
1221 if (m->peerchain_size() > 0)
1225 m->peerchain_size() - 1).nodepubkey())};
1227 return badData(
"Invalid pubKey");
1232 if (!m->has_nodepubkey())
1235 if (!m->has_endpoint())
1241 m->set_endpoint(
"0");
1244 m->mutable_peerchain()->RemoveLast();
1245 peer->send(std::make_shared<Message>(
1246 *m, protocol::mtPEER_SHARD_INFO));
1249 "Relayed TMPeerShardInfo to peer with IP " <<
1257 "Unable to route shard info";
1265 if (!
from_string(shardIndexes, m->shardindexes()))
1266 return badData(
"Invalid shard indexes");
1269 boost::optional<std::uint32_t> latestShard;
1271 auto const curLedgerSeq {
1275 earliestShard = shardStore->earliestShardIndex();
1276 if (curLedgerSeq >= shardStore->earliestLedgerSeq())
1277 latestShard = shardStore->seqToShardIndex(curLedgerSeq);
1281 auto const earliestLedgerSeq {
1284 if (curLedgerSeq >= earliestLedgerSeq)
1289 if (boost::icl::first(shardIndexes) < earliestShard ||
1290 (latestShard && boost::icl::last(shardIndexes) > latestShard))
1292 return badData(
"Invalid shard indexes");
1298 if (m->has_endpoint())
1300 if (m->endpoint() !=
"0")
1305 return badData(
"Invalid incoming endpoint: " + m->endpoint());
1306 endpoint = std::move(*result);
1316 if (m->has_nodepubkey())
1327 it->second.endpoint = std::move(endpoint);
1330 it->second.shardIndexes += shardIndexes;
1336 shardInfo.
endpoint = std::move(endpoint);
1338 shardInfo_.emplace(publicKey, std::move(shardInfo));
1343 "Consumed TMPeerShardInfo originating from public key " <<
1345 " shard indexes " << m->shardindexes();
1347 if (m->has_lastlink())
1362 if (m->endpoints_v2().size())
1364 endpoints.
reserve (m->endpoints_v2().size());
1365 for (
auto const& tm : m->endpoints_v2 ())
1372 "failed to parse incoming endpoint: {" <<
1373 tm.endpoint() <<
"}";
1390 "got v2 EP: " << endpoints.
back().address <<
1391 ", hops = " << endpoints.
back().hops;
1398 endpoints.
reserve (m->endpoints().size());
1399 for (
int i = 0; i < m->endpoints ().size (); ++i)
1402 protocol::TMEndpoint
const& tm (m->endpoints(i));
1405 endpoint.
hops = tm.hops();
1408 if (endpoint.
hops > 0)
1411 addr.s_addr = tm.ipv4().ipv4();
1424 tm.ipv4().ipv4port ());
1428 "got v1 EP: " << endpoints.
back().address <<
1429 ", hops = " << endpoints.
back().hops;
1433 if (! endpoints.
empty())
1449 "Need network ledger";
1457 auto stx = std::make_shared<STTx const>(sit);
1458 uint256 txID = stx->getTransactionID ();
1479 bool checkSignature =
true;
1482 if (! m->has_deferred () || ! m->deferred ())
1486 flags |= SF_TRUSTED;
1493 checkSignature =
false;
1498 constexpr
int max_transactions = 250;
1513 flags, checkSignature, stx] (
Job&) {
1514 if (
auto peer = weak.lock())
1515 peer->checkTransaction(flags,
1516 checkSignature, stx);
1523 strHex(m->rawtransaction ());
1535 if (
auto peer = weak.
lock())
1543 protocol::TMLedgerData& packet = *m;
1545 if (m->nodes ().size () <= 0)
1551 if (m->has_requestcookie ())
1556 m->clear_requestcookie ();
1557 target->send (std::make_shared<Message> (
1558 packet, protocol::mtLEDGER_DATA));
1562 JLOG(
p_journal_.
info()) <<
"Unable to route TX/ledger data reply";
1570 JLOG(
p_journal_.
warn()) <<
"TX candidate reply with invalid hash size";
1575 uint256 const hash {m->ledgerhash()};
1577 if (m->type () == protocol::liTS_CANDIDATE)
1584 [weak, hash, journal, m] (
Job&) {
1585 if (
auto peer = weak.
lock())
1586 peer->peerTXData(hash, m, journal);
1602 protocol::TMProposeSet&
set = *m;
1605 set.set_hops(
set.hops() + 1);
1611 if ((boost::algorithm::clamp(sig.size(), 64, 72) != sig.size()) ||
1627 uint256 const proposeHash{
set.currenttxhash()};
1628 uint256 const prevLedger{
set.previousledger()};
1634 proposeHash, prevLedger,
set.proposeseq(),
1635 closeTime, publicKey.slice(), sig);
1661 "Proposal: " << (isTrusted ?
"trusted" :
"UNTRUSTED");
1679 if (
auto peer = weak.lock())
1680 peer->checkPropose(job, m,
proposal);
1689 if (!m->has_networktime ())
1694 if (!
last_status_.has_newstatus () || m->has_newstatus ())
1699 protocol::NodeStatus status =
last_status_.newstatus ();
1701 m->set_newstatus (status);
1705 if (m->newevent () == protocol::neLOST_SYNC)
1707 bool outOfSync {
false};
1728 bool const peerChangedLedgers {
1735 if (peerChangedLedgers)
1746 if (m->has_ledgerhashprevious() &&
1757 if (peerChangedLedgers)
1768 if (m->has_firstseq () && m->has_lastseq())
1779 if (m->has_ledgerseq() &&
1790 if (m->has_newstatus ())
1792 switch (m->newstatus ())
1794 case protocol::nsCONNECTING:
1795 j[jss::status] =
"CONNECTING";
1797 case protocol::nsCONNECTED:
1798 j[jss::status] =
"CONNECTED";
1800 case protocol::nsMONITORING:
1801 j[jss::status] =
"MONITORING";
1803 case protocol::nsVALIDATING:
1804 j[jss::status] =
"VALIDATING";
1806 case protocol::nsSHUTTING:
1807 j[jss::status] =
"SHUTTING";
1812 if (m->has_newevent())
1814 switch (m->newevent ())
1816 case protocol::neCLOSING_LEDGER:
1817 j[jss::action] =
"CLOSING_LEDGER";
1819 case protocol::neACCEPTED_LEDGER:
1820 j[jss::action] =
"ACCEPTED_LEDGER";
1822 case protocol::neSWITCHED_LEDGER:
1823 j[jss::action] =
"SWITCHED_LEDGER";
1825 case protocol::neLOST_SYNC:
1826 j[jss::action] =
"LOST_SYNC";
1831 if (m->has_ledgerseq ())
1833 j[jss::ledger_index] = m->ledgerseq();
1836 if (m->has_ledgerhash ())
1838 uint256 closedLedgerHash {};
1840 std::lock_guard sl(recentLock_);
1841 closedLedgerHash = closedLedgerHash_;
1843 j[jss::ledger_hash] =
to_string (closedLedgerHash);
1846 if (m->has_networktime ())
1848 j[jss::date] = Json::UInt (m->networktime());
1851 if (m->has_firstseq () && m->has_lastseq ())
1853 j[jss::ledger_index_min] =
1854 Json::UInt (m->firstseq ());
1855 j[jss::ledger_index_max] =
1856 Json::UInt (m->lastseq ());
1872 serverSeq = maxLedger_;
1878 checkSanity (serverSeq, validationSeq);
1887 if (
diff < Tuning::saneLedgerLimit)
1890 sanity_ = Sanity::sane;
1893 if ((
diff > Tuning::insaneLedgerLimit) && (sanity_.load() != Sanity::insane))
1898 sanity_ = Sanity::insane;
1899 insaneTime_ = clock_type::now();
1905 void PeerImp::check ()
1907 if (m_inbound || (sanity_.load() == Sanity::sane))
1910 clock_type::time_point insaneTime;
1914 insaneTime = insaneTime_;
1917 bool reject =
false;
1919 if (sanity_.load() == Sanity::insane)
1920 reject = (insaneTime - clock_type::now())
1923 if (sanity_.load() == Sanity::unknown)
1924 reject = (insaneTime - clock_type::now())
1929 overlay_.peerFinder().on_failure (slot_);
1944 fee_ = Resource::feeInvalidRequest;
1948 uint256 const hash {m->hash()};
1950 if (m->status () == protocol::tsHAVE)
1955 recentTxSets_.end (), hash) != recentTxSets_.end ())
1957 fee_ = Resource::feeUnwantedData;
1961 if (recentTxSets_.size () == 128)
1962 recentTxSets_.pop_front ();
1964 recentTxSets_.push_back (hash);
1973 if (!supportsFeature(ProtocolFeature::ValidatorListPropagation))
1975 JLOG(p_journal_.debug())
1976 <<
"ValidatorList: received validator list from peer using "
1977 <<
"protocol version " << to_string(protocol_)
1978 <<
" which shouldn't support this feature.";
1979 fee_ = Resource::feeUnwantedData;
1982 auto const&
manifest = m->manifest();
1983 auto const& blob = m->blob();
1984 auto const& signature = m->signature();
1985 auto const version = m->version();
1988 JLOG(p_journal_.debug()) <<
"Received validator list from " <<
1989 remote_address_.to_string() <<
" (" << id_ <<
")";
1991 if (! app_.getHashRouter ().addSuppressionPeer(hash, id_))
1993 JLOG(p_journal_.debug()) <<
1994 "ValidatorList: received duplicate validator list";
1998 fee_ = Resource::feeUnwantedData;
2002 auto const applyResult = app_.validators().applyListAndBroadcast (
2007 remote_address_.to_string(),
2010 app_.getHashRouter());
2011 auto const disp = applyResult.disposition;
2013 JLOG(p_journal_.debug()) <<
"Processed validator list from " <<
2014 (applyResult.publisherKey ?
strHex(*applyResult.publisherKey) :
2015 "unknown or invalid publisher") <<
" from " <<
2016 remote_address_.to_string() <<
" (" << id_ <<
") with result " <<
2021 case ListDisposition::accepted:
2022 JLOG (p_journal_.debug()) <<
2023 "Applied new validator list from peer " << remote_address_;
2027 assert(applyResult.sequence && applyResult.publisherKey);
2028 auto const& pubKey = *applyResult.publisherKey;
2030 if (
auto const iter = publisherListSequences_.find(pubKey);
2031 iter != publisherListSequences_.end())
2033 assert(iter->second < *applyResult.sequence);
2036 publisherListSequences_[pubKey] = *applyResult.sequence;
2039 case ListDisposition::same_sequence:
2040 JLOG (p_journal_.warn()) <<
2041 "Validator list with current sequence from peer " <<
2046 fee_ = Resource::feeUnwantedData;
2050 assert(applyResult.sequence && applyResult.publisherKey);
2051 assert(publisherListSequences_[*applyResult.publisherKey]
2052 == *applyResult.sequence);
2057 case ListDisposition::stale:
2058 JLOG (p_journal_.warn()) <<
2059 "Stale validator list from peer " << remote_address_;
2062 fee_ = Resource::feeBadData;
2064 case ListDisposition::untrusted:
2065 JLOG (p_journal_.warn()) <<
2066 "Untrusted validator list from peer " << remote_address_;
2070 fee_ = Resource::feeUnwantedData;
2072 case ListDisposition::invalid:
2073 JLOG (p_journal_.warn()) <<
2074 "Invalid validator list from peer " << remote_address_;
2076 fee_ = Resource::feeInvalidSignature;
2078 case ListDisposition::unsupported_version:
2079 JLOG (p_journal_.warn()) <<
2080 "Unsupported version validator list from peer " <<
2084 fee_ = Resource::feeBadData;
2092 JLOG(p_journal_.warn()) <<
2093 "ValidatorList: Exception, " << e.
what() <<
2094 " from peer " << remote_address_;
2095 fee_ = Resource::feeBadData;
2102 auto const closeTime = app_.timeKeeper().closeTime();
2104 if (m->has_hops() && ! cluster())
2105 m->set_hops(m->hops() + 1);
2107 if (m->validation ().size () < 50)
2109 JLOG(p_journal_.warn()) <<
"Validation: Too small";
2110 fee_ = Resource::feeInvalidRequest;
2119 val = std::make_shared<STValidation>(
2123 app_.validatorManifests().getMasterKey(pk));
2126 val->setSeen (closeTime);
2129 if (!
isCurrent(app_.getValidations().parms(),
2130 app_.timeKeeper().closeTime(),
2132 val->getSeenTime()))
2134 JLOG(p_journal_.trace()) <<
"Validation: Not current";
2135 fee_ = Resource::feeUnwantedData;
2139 if (! app_.getHashRouter ().addSuppressionPeer(
2142 JLOG(p_journal_.trace()) <<
"Validation: duplicate";
2146 auto const isTrusted =
2147 app_.validators().trusted(val->getSignerPublic ());
2149 if (!isTrusted && (sanity_.load () == Sanity::insane))
2151 JLOG(p_journal_.debug()) <<
2152 "Validation: dropping untrusted from insane peer";
2154 if (isTrusted || cluster() ||
2155 ! app_.getFeeTrack ().isLoadedLocal ())
2158 app_.getJobQueue ().addJob (
2160 "recvValidation->checkValidation",
2161 [weak, val, m] (
Job&)
2163 if (
auto peer = weak.
lock())
2164 peer->checkValidation(val, m);
2169 JLOG(p_journal_.debug()) <<
2170 "Validation: Dropping UNTRUSTED (load)";
2175 JLOG(p_journal_.warn()) <<
2176 "Validation: Exception, " << e.
what();
2177 fee_ = Resource::feeInvalidRequest;
2184 protocol::TMGetObjectByHash& packet = *m;
2186 if (packet.query ())
2189 if (send_queue_.size() >= Tuning::dropSendQueue)
2191 JLOG(p_journal_.debug()) <<
"GetObject: Large send queue";
2195 if (packet.type () == protocol::TMGetObjectByHash::otFETCH_PACK)
2201 fee_ = Resource::feeMediumBurdenPeer;
2203 protocol::TMGetObjectByHash reply;
2205 reply.set_query (
false);
2207 if (packet.has_seq())
2208 reply.set_seq(packet.seq());
2210 reply.set_type (packet.type ());
2212 if (packet.has_ledgerhash ())
2213 reply.set_ledgerhash (packet.ledgerhash ());
2216 for (
int i = 0; i < packet.objects_size (); ++i)
2218 auto const& obj = packet.objects (i);
2221 uint256 const hash {obj.hash()};
2224 std::uint32_t seq {obj.has_ledgerseq() ? obj.ledgerseq() : 0};
2225 auto hObj {app_.getNodeStore().fetch (hash, seq)};
2228 if (
auto shardStore = app_.getShardStore())
2230 if (seq >= shardStore->earliestLedgerSeq())
2231 hObj = shardStore->fetch(hash, seq);
2236 protocol::TMIndexedObject& newObj = *reply.add_objects ();
2237 newObj.set_hash (hash.begin (), hash.size ());
2238 newObj.set_data (&hObj->getData ().front (),
2239 hObj->getData ().size ());
2241 if (obj.has_nodeid ())
2242 newObj.set_index (obj.nodeid ());
2243 if (obj.has_ledgerseq())
2244 newObj.set_ledgerseq(obj.ledgerseq());
2251 JLOG(p_journal_.trace()) <<
2252 "GetObj: " << reply.objects_size () <<
2253 " of " << packet.objects_size ();
2254 send (std::make_shared<Message> (reply, protocol::mtGET_OBJECTS));
2261 bool progress =
false;
2263 for (
int i = 0; i < packet.objects_size(); ++i)
2265 const protocol::TMIndexedObject& obj = packet.objects (i);
2269 if (obj.has_ledgerseq())
2271 if (obj.ledgerseq() != pLSeq)
2273 if (pLDo && (pLSeq != 0))
2275 JLOG(p_journal_.debug()) <<
2276 "GetObj: Full fetch pack for " << pLSeq;
2278 pLSeq = obj.ledgerseq();
2279 pLDo = !app_.getLedgerMaster().haveLedger (pLSeq);
2283 JLOG(p_journal_.debug()) <<
2284 "GetObj: Late fetch pack for " << pLSeq;
2293 uint256 const hash {obj.hash()};
2296 std::make_shared< Blob > (
2297 obj.data().begin(), obj.data().end()));
2299 app_.getLedgerMaster().addFetchPack (hash, data);
2304 if (pLDo && (pLSeq != 0))
2306 JLOG(p_journal_.debug()) <<
2307 "GetObj: Partial fetch pack for " << pLSeq;
2309 if (packet.type () == protocol::TMGetObjectByHash::otFETCH_PACK)
2310 app_.getLedgerMaster ().gotFetchPack (progress, pLSeq);
2322 (void) lockedRecentLock;
2325 recentLedgers_.end(), hash) != recentLedgers_.end())
2330 if (recentLedgers_.size () == 128)
2331 recentLedgers_.pop_front ();
2333 recentLedgers_.push_back (hash);
2342 if (app_.getFeeTrack ().isLoadedLocal () ||
2343 (app_.getLedgerMaster().getValidatedLedgerAge() > 40s) ||
2344 (app_.getJobQueue().getJobCount(
jtPACK) > 10))
2346 JLOG(p_journal_.info()) <<
"Too busy to make fetch pack";
2352 JLOG(p_journal_.warn()) <<
"FetchPack hash size malformed";
2353 fee_ = Resource::feeInvalidRequest;
2357 fee_ = Resource::feeHighBurdenPeer;
2359 uint256 const hash {packet->ledgerhash()};
2362 auto elapsed = UptimeClock::now();
2363 auto const pap = &app_;
2364 app_.getJobQueue ().addJob (
2366 [pap, weak, packet, hash, elapsed] (
Job&) {
2367 pap->getLedgerMaster().makeFetchPack(
2368 weak, packet, hash, elapsed);
2373 PeerImp::checkTransaction (
int flags,
2382 app_.getLedgerMaster().getValidLedgerIndex()))
2384 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2385 charge (Resource::feeUnwantedData);
2393 app_.getHashRouter(),
2395 app_.getLedgerMaster().getValidatedRules(),
2397 valid != Validity::Valid)
2399 if (!validReason.empty())
2401 JLOG(p_journal_.trace()) <<
2402 "Exception checking transaction: " <<
2407 app_.getHashRouter().setFlags(stx->getTransactionID(), SF_BAD);
2408 charge(Resource::feeInvalidSignature);
2415 stx->getTransactionID(), Validity::Valid);
2419 auto tx = std::make_shared<Transaction> (
2422 if (tx->getStatus () ==
INVALID)
2424 if (! reason.
empty ())
2426 JLOG(p_journal_.trace()) <<
2427 "Exception checking transaction: " << reason;
2429 app_.getHashRouter ().setFlags (stx->getTransactionID (), SF_BAD);
2430 charge (Resource::feeInvalidSignature);
2434 bool const trusted (flags & SF_TRUSTED);
2435 app_.getOPs ().processTransaction (
2436 tx, trusted,
false, NetworkOPs::FailHard::no);
2440 app_.getHashRouter ().setFlags (stx->getTransactionID (), SF_BAD);
2441 charge (Resource::feeBadData);
2447 PeerImp::checkPropose (
Job& job,
2453 JLOG(p_journal_.trace()) <<
2454 "Checking " << (isTrusted ?
"trusted" :
"UNTRUSTED") <<
" proposal";
2457 protocol::TMProposeSet&
set = *packet;
2459 if (! cluster() && !peerPos.
checkSign ())
2461 JLOG(p_journal_.warn()) <<
2462 "Proposal fails sig check";
2463 charge (Resource::feeInvalidSignature);
2469 app_.getOPs ().processTrustedProposal (peerPos, packet);
2477 JLOG(p_journal_.trace()) <<
2478 "relaying UNTRUSTED proposal";
2483 JLOG(p_journal_.debug()) <<
2484 "Not relaying UNTRUSTED proposal";
2496 if (! cluster() && !val->isValid())
2498 JLOG(p_journal_.warn()) <<
2499 "Validation is invalid";
2500 charge (Resource::feeInvalidRequest);
2509 overlay_.relay(*packet, suppression);
2514 JLOG(p_journal_.trace()) <<
2515 "Exception processing validation";
2516 charge (Resource::feeInvalidRequest);
2533 if (p->hasTxSet(rootHash) && p.get() != skip)
2535 auto score = p->getScore (true);
2536 if (! ret || (score > retScore))
2561 if (p->hasLedger(ledgerHash, ledger) &&
2564 auto score = p->getScore (true);
2565 if (! ret || (score > retScore))
2580 protocol::TMGetLedger& packet = *m;
2582 SHAMap const* map =
nullptr;
2583 protocol::TMLedgerData reply;
2584 bool fatLeaves =
true;
2587 if (packet.has_requestcookie ())
2588 reply.set_requestcookie (packet.requestcookie ());
2592 if (packet.itype () == protocol::liTS_CANDIDATE)
2595 JLOG(p_journal_.trace()) <<
"GetLedger: Tx candidate set";
2597 if (!packet.has_ledgerhash() ||
2600 charge (Resource::feeInvalidRequest);
2601 JLOG(p_journal_.warn()) <<
"GetLedger: Tx candidate set invalid";
2605 uint256 const txHash {packet.ledgerhash()};
2607 shared = app_.getInboundTransactions().getSet (txHash,
false);
2612 if (packet.has_querytype () && !packet.has_requestcookie ())
2614 JLOG(p_journal_.debug()) <<
"GetLedger: Routing Tx set request";
2617 overlay_, txHash,
this);
2620 JLOG(p_journal_.info()) <<
"GetLedger: Route TX set failed";
2624 packet.set_requestcookie (
id ());
2625 v->send (std::make_shared<Message> (
2626 packet, protocol::mtGET_LEDGER));
2630 JLOG(p_journal_.debug()) <<
"GetLedger: Can't provide map ";
2631 charge (Resource::feeInvalidRequest);
2635 reply.set_ledgerseq (0);
2636 reply.set_ledgerhash (txHash.begin (), txHash.size ());
2637 reply.set_type (protocol::liTS_CANDIDATE);
2642 if (send_queue_.size() >= Tuning::dropSendQueue)
2644 JLOG(p_journal_.debug()) <<
"GetLedger: Large send queue";
2648 if (app_.getFeeTrack().isLoadedLocal() && ! cluster())
2650 JLOG(p_journal_.debug()) <<
"GetLedger: Too busy";
2655 JLOG(p_journal_.trace()) <<
"GetLedger: Received";
2657 if (packet.has_ledgerhash ())
2661 charge (Resource::feeInvalidRequest);
2662 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid request";
2666 uint256 const ledgerhash {packet.ledgerhash()};
2667 logMe +=
"LedgerHash:";
2668 logMe += to_string (ledgerhash);
2669 ledger = app_.getLedgerMaster ().getLedgerByHash (ledgerhash);
2671 if (!ledger && packet.has_ledgerseq())
2673 if (
auto shardStore = app_.getShardStore())
2675 auto seq = packet.ledgerseq();
2676 if (seq >= shardStore->earliestLedgerSeq())
2677 ledger = shardStore->fetchLedger(ledgerhash, seq);
2683 JLOG(p_journal_.trace()) <<
2684 "GetLedger: Don't have " << ledgerhash;
2687 if (!ledger && (packet.has_querytype () &&
2688 !packet.has_requestcookie ()))
2693 packet.has_ledgerseq() ? packet.ledgerseq() : 0,
this);
2696 JLOG(p_journal_.trace()) <<
"GetLedger: Cannot route";
2700 packet.set_requestcookie (
id ());
2701 v->send (std::make_shared<Message>(
2702 packet, protocol::mtGET_LEDGER));
2703 JLOG(p_journal_.debug()) <<
"GetLedger: Request routed";
2707 else if (packet.has_ledgerseq ())
2709 if (packet.ledgerseq() <
2710 app_.getLedgerMaster().getEarliestFetch())
2712 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2715 ledger = app_.getLedgerMaster ().getLedgerBySeq (
2716 packet.ledgerseq ());
2719 JLOG(p_journal_.debug()) <<
2720 "GetLedger: Don't have " << packet.ledgerseq ();
2723 else if (packet.has_ltype () && (packet.ltype () == protocol::ltCLOSED) )
2725 ledger = app_.getLedgerMaster ().getClosedLedger ();
2726 assert(! ledger->open());
2730 if (ledger && ledger->info().open)
2731 ledger = app_.getLedgerMaster ().getLedgerBySeq (
2732 ledger->info().seq - 1);
2737 charge (Resource::feeInvalidRequest);
2738 JLOG(p_journal_.warn()) <<
"GetLedger: Unknown request";
2742 if ((!ledger) || (packet.has_ledgerseq () && (
2743 packet.ledgerseq () != ledger->info().seq)))
2745 charge (Resource::feeInvalidRequest);
2749 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid sequence";
2754 if (!packet.has_ledgerseq() && (ledger->info().seq <
2755 app_.getLedgerMaster().getEarliestFetch()))
2757 JLOG(p_journal_.debug()) <<
"GetLedger: Early ledger request";
2762 auto const lHash = ledger->info().hash;
2763 reply.set_ledgerhash (lHash.begin (), lHash.size ());
2764 reply.set_ledgerseq (ledger->info().seq);
2765 reply.set_type (packet.itype ());
2767 if (packet.itype () == protocol::liBASE)
2770 JLOG(p_journal_.trace()) <<
"GetLedger: Base data";
2772 addRaw(ledger->info(), nData);
2773 reply.add_nodes ()->set_nodedata (
2776 auto const& stateMap = ledger->stateMap ();
2777 if (stateMap.getHash() != beast::zero)
2781 if (stateMap.getRootNode(rootNode,
snfWIRE))
2783 reply.add_nodes ()->set_nodedata (
2786 if (ledger->info().txHash != beast::zero)
2788 auto const& txMap = ledger->txMap ();
2790 if (txMap.getHash() != beast::zero)
2794 if (txMap.getRootNode (rootNode,
snfWIRE))
2795 reply.add_nodes ()->set_nodedata (
2803 auto oPacket = std::make_shared<Message> (
2804 reply, protocol::mtLEDGER_DATA);
2809 if (packet.itype () == protocol::liTX_NODE)
2811 map = &ledger->txMap ();
2813 logMe += to_string (map->
getHash ());
2815 else if (packet.itype () == protocol::liAS_NODE)
2817 map = &ledger->stateMap ();
2819 logMe += to_string (map->
getHash ());
2823 if (!map || (packet.nodeids_size () == 0))
2825 JLOG(p_journal_.warn()) <<
2826 "GetLedger: Can't find map or empty request";
2827 charge (Resource::feeInvalidRequest);
2831 JLOG(p_journal_.trace()) <<
"GetLedger: " << logMe;
2834 packet.has_querydepth() ?
2835 (
std::min(packet.querydepth(), 3u)) :
2836 (isHighLatency() ? 2 : 1);
2839 (i < packet.nodeids().size() &&
2840 (reply.nodes().size() < Tuning::maxReplyNodes)); ++i)
2842 SHAMapNodeID mn (packet.nodeids (i).data (), packet.nodeids (i).size ());
2846 JLOG(p_journal_.warn()) <<
"GetLedger: Invalid node " << logMe;
2847 charge (Resource::feeInvalidRequest);
2856 if (map->
getNodeFat(mn, nodeIDs, rawNodes, fatLeaves, depth))
2858 assert (nodeIDs.
size () == rawNodes.
size ());
2859 JLOG(p_journal_.trace()) <<
2860 "GetLedger: getNodeFat got " << rawNodes.
size () <<
" nodes";
2864 for (nodeIDIterator = nodeIDs.
begin (),
2865 rawNodeIterator = rawNodes.
begin ();
2866 nodeIDIterator != nodeIDs.
end ();
2867 ++nodeIDIterator, ++rawNodeIterator)
2870 nodeIDIterator->addIDRaw (nID);
2871 protocol::TMLedgerNode* node = reply.add_nodes ();
2873 node->set_nodedata (&rawNodeIterator->
front (),
2874 rawNodeIterator->
size ());
2879 JLOG(p_journal_.warn()) <<
2880 "GetLedger: getNodeFat returns false";
2887 if (packet.itype () == protocol::liTS_CANDIDATE)
2888 info =
"TS candidate";
2889 else if (packet.itype () == protocol::liBASE)
2890 info =
"Ledger base";
2891 else if (packet.itype () == protocol::liTX_NODE)
2893 else if (packet.itype () == protocol::liAS_NODE)
2896 if (!packet.has_ledgerhash ())
2897 info +=
", no hash specified";
2899 JLOG(p_journal_.warn()) <<
2900 "getNodeFat( " << mn <<
") throws exception: " << info;
2904 JLOG(p_journal_.info()) <<
2905 "Got request for " << packet.nodeids().size() <<
" nodes at depth " <<
2906 depth <<
", return " << reply.nodes().size() <<
" nodes";
2908 auto oPacket = std::make_shared<Message> (
2909 reply, protocol::mtLEDGER_DATA);
2918 app_.getInboundTransactions().gotData (hash, shared_from_this(), pPacket);
2922 PeerImp::getScore (
bool haveItem)
const
2926 static const int spRandomMax = 9999;
2930 static const int spHaveItem = 10000;
2935 static const int spLatency = 30;
2938 static const int spNoLatency = 8000;
2943 score += spHaveItem;
2945 boost::optional<std::chrono::milliseconds> latency;
2952 score -= latency->count() * spLatency;
2954 score -= spNoLatency;
2960 PeerImp::isHighLatency()
const
2963 return latency_ >= Tuning::peerHighLatency;
2969 using namespace std::chrono_literals;
2972 totalBytes_ += bytes;
2973 accumBytes_ += bytes;
2974 auto const timeElapsed = clock_type::now() - intervalStart_;
2975 auto const timeElapsedInSecs = std::chrono::duration_cast<std::chrono::seconds>(timeElapsed);
2977 if (timeElapsedInSecs >= 1s)
2979 auto const avgBytes = accumBytes_ / timeElapsedInSecs.count();
2980 rollingAvg_.push_back(avgBytes);
2982 auto const totalBytes =
std::accumulate(rollingAvg_.begin(), rollingAvg_.end(), 0ull);
2983 rollingAvgBytes_ = totalBytes / rollingAvg_.size();
2985 intervalStart_ = clock_type::now();
2991 PeerImp::Metrics::average_bytes()
const {
2993 return rollingAvgBytes_;
2997 PeerImp::Metrics::total_bytes()
const {