1#include <xrpl/server/NetworkOPs.h>
3#include <xrpld/app/consensus/RCLConsensus.h>
4#include <xrpld/app/consensus/RCLCxPeerPos.h>
5#include <xrpld/app/consensus/RCLValidations.h>
6#include <xrpld/app/ledger/AcceptedLedger.h>
7#include <xrpld/app/ledger/InboundLedger.h>
8#include <xrpld/app/ledger/InboundLedgers.h>
9#include <xrpld/app/ledger/LedgerMaster.h>
10#include <xrpld/app/ledger/LedgerToJson.h>
11#include <xrpld/app/ledger/LocalTxs.h>
12#include <xrpld/app/ledger/OpenLedger.h>
13#include <xrpld/app/ledger/TransactionMaster.h>
14#include <xrpld/app/main/LoadManager.h>
15#include <xrpld/app/main/Tuning.h>
16#include <xrpld/app/misc/DeliverMax.h>
17#include <xrpld/app/misc/FeeVote.h>
18#include <xrpld/app/misc/Transaction.h>
19#include <xrpld/app/misc/TxQ.h>
20#include <xrpld/app/misc/ValidatorKeys.h>
21#include <xrpld/app/misc/ValidatorList.h>
22#include <xrpld/app/misc/make_NetworkOPs.h>
23#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
24#include <xrpld/core/Config.h>
25#include <xrpld/overlay/Cluster.h>
26#include <xrpld/overlay/ClusterNode.h>
27#include <xrpld/overlay/Overlay.h>
28#include <xrpld/overlay/predicates.h>
29#include <xrpld/rpc/BookChanges.h>
30#include <xrpld/rpc/CTID.h>
31#include <xrpld/rpc/ServerHandler.h>
32#include <xrpld/rpc/detail/SyntheticFields.h>
34#include <xrpl/basics/Log.h>
35#include <xrpl/basics/ToString.h>
36#include <xrpl/basics/UnorderedContainers.h>
37#include <xrpl/basics/UptimeClock.h>
38#include <xrpl/basics/base_uint.h>
39#include <xrpl/basics/chrono.h>
40#include <xrpl/basics/contract.h>
41#include <xrpl/basics/mulDiv.h>
42#include <xrpl/basics/safe_cast.h>
43#include <xrpl/basics/scope.h>
44#include <xrpl/basics/strHex.h>
45#include <xrpl/beast/clock/abstract_clock.h>
46#include <xrpl/beast/insight/Collector.h>
47#include <xrpl/beast/insight/Gauge.h>
48#include <xrpl/beast/insight/Hook.h>
49#include <xrpl/beast/net/IPEndpoint.h>
50#include <xrpl/beast/utility/Zero.h>
51#include <xrpl/beast/utility/instrumentation.h>
52#include <xrpl/beast/utility/rngfill.h>
53#include <xrpl/config/Constants.h>
54#include <xrpl/consensus/ConsensusParms.h>
55#include <xrpl/consensus/ConsensusTypes.h>
56#include <xrpl/core/ClosureCounter.h>
57#include <xrpl/core/HashRouter.h>
58#include <xrpl/core/Job.h>
59#include <xrpl/core/NetworkIDService.h>
60#include <xrpl/core/PerfLog.h>
61#include <xrpl/core/ServiceRegistry.h>
62#include <xrpl/crypto/RFC1751.h>
63#include <xrpl/crypto/csprng.h>
64#include <xrpl/git/Git.h>
65#include <xrpl/json/json_forwards.h>
66#include <xrpl/json/json_value.h>
67#include <xrpl/json/json_writer.h>
68#include <xrpl/ledger/AcceptedLedgerTx.h>
69#include <xrpl/ledger/AmendmentTable.h>
70#include <xrpl/ledger/ApplyView.h>
71#include <xrpl/ledger/CanonicalTXSet.h>
72#include <xrpl/ledger/Ledger.h>
73#include <xrpl/ledger/OpenView.h>
74#include <xrpl/ledger/OrderBookDB.h>
75#include <xrpl/ledger/ReadView.h>
76#include <xrpl/ledger/helpers/DirectoryHelpers.h>
77#include <xrpl/ledger/helpers/MPTokenHelpers.h>
78#include <xrpl/ledger/helpers/TokenHelpers.h>
79#include <xrpl/protocol/AccountID.h>
80#include <xrpl/protocol/AmountConversions.h>
81#include <xrpl/protocol/ApiVersion.h>
82#include <xrpl/protocol/Book.h>
83#include <xrpl/protocol/BuildInfo.h>
84#include <xrpl/protocol/ErrorCodes.h>
85#include <xrpl/protocol/Feature.h>
86#include <xrpl/protocol/Fees.h>
87#include <xrpl/protocol/Indexes.h>
88#include <xrpl/protocol/Issue.h>
89#include <xrpl/protocol/KeyType.h>
90#include <xrpl/protocol/LedgerFormats.h>
91#include <xrpl/protocol/MPTAmount.h>
92#include <xrpl/protocol/MPTIssue.h>
93#include <xrpl/protocol/MultiApiJson.h>
94#include <xrpl/protocol/Protocol.h>
95#include <xrpl/protocol/PublicKey.h>
96#include <xrpl/protocol/RPCErr.h>
97#include <xrpl/protocol/Rate.h>
98#include <xrpl/protocol/SField.h>
99#include <xrpl/protocol/STAmount.h>
100#include <xrpl/protocol/STTx.h>
101#include <xrpl/protocol/SecretKey.h>
102#include <xrpl/protocol/Seed.h>
103#include <xrpl/protocol/Serializer.h>
104#include <xrpl/protocol/TER.h>
105#include <xrpl/protocol/TxFlags.h>
106#include <xrpl/protocol/TxFormats.h>
107#include <xrpl/protocol/UintTypes.h>
108#include <xrpl/protocol/Units.h>
109#include <xrpl/protocol/XRPAmount.h>
110#include <xrpl/protocol/jss.h>
111#include <xrpl/protocol/tokens.h>
112#include <xrpl/rdb/RelationalDatabase.h>
113#include <xrpl/resource/Fees.h>
114#include <xrpl/resource/Gossip.h>
115#include <xrpl/resource/ResourceManager.h>
116#include <xrpl/server/InfoSub.h>
117#include <xrpl/server/LoadFeeTrack.h>
118#include <xrpl/server/Manifest.h>
119#include <xrpl/shamap/SHAMap.h>
120#include <xrpl/tx/apply.h>
122#include <boost/asio/error.hpp>
123#include <boost/asio/io_context.hpp>
124#include <boost/asio/ip/host_name.hpp>
125#include <boost/asio/steady_timer.hpp>
126#include <boost/system/detail/errc.hpp>
127#include <boost/system/detail/error_code.hpp>
128#include <boost/system/system_error.hpp>
188 "xrpl::NetworkOPsImp::TransactionStatus::TransactionStatus : "
296 return !(*
this != b);
315 boost::asio::io_context& ioCtx,
332 registry.getInboundTransactions(),
333 beast::getAbstractClock<
std::chrono::steady_clock>(),
337 validatorKeys.keys ? validatorKeys.keys->publicKey : decltype(
validatorPK_){})
339 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
527 getServerInfo(
bool human,
bool admin,
bool counters)
override;
555 TER result)
override;
690 catch (boost::system::system_error
const& e)
692 JLOG(
journal_.error()) <<
"NetworkOPs: heartbeatTimer cancel error: " << e.what();
699 catch (boost::system::system_error
const& e)
701 JLOG(
journal_.error()) <<
"NetworkOPs: clusterTimer cancel error: " << e.what();
708 catch (boost::system::system_error
const& e)
711 <<
"NetworkOPs: accountHistoryTxTimer cancel error: " << e.what();
715 using namespace std::chrono_literals;
725 boost::asio::steady_timer& timer,
908 template <
typename OuterMap,
typename BeforeErase>
914 BeforeErase&& beforeErase);
1043 template <
class Handler>
1045 :
hook(collector->makeHook(handler))
1047 collector->makeGauge(
"State_Accounting",
"Disconnected_duration"))
1048 ,
connectedDuration(collector->makeGauge(
"State_Accounting",
"Connected_duration"))
1049 ,
syncingDuration(collector->makeGauge(
"State_Accounting",
"Syncing_duration"))
1050 ,
trackingDuration(collector->makeGauge(
"State_Accounting",
"Tracking_duration"))
1051 ,
fullDuration(collector->makeGauge(
"State_Accounting",
"Full_duration"))
1053 collector->makeGauge(
"State_Accounting",
"Disconnected_transitions"))
1055 collector->makeGauge(
"State_Accounting",
"Connected_transitions"))
1056 ,
syncingTransitions(collector->makeGauge(
"State_Accounting",
"Syncing_transitions"))
1058 ,
fullTransitions(collector->makeGauge(
"State_Accounting",
"Full_transitions"))
1087 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
1147 static std::string const kHostname = boost::asio::ip::host_name();
1154 static std::string const kShroudedHostId = [
this]() {
1155 auto const&
id =
registry_.get().getApp().nodeIdentity();
1160 return kShroudedHostId;
1169 if (
registry_.get().getCluster().size() != 0)
1175 boost::asio::steady_timer& timer,
1181 if (
auto optionalCountedHandler =
1183 if ((e.value() == boost::system::errc::success) && (!jobQueue_.isStopped()))
1188 if (e.value() != boost::system::errc::success &&
1189 e.value() != boost::asio::error::operation_aborted)
1192 JLOG(journal_.error())
1193 <<
"Timer got error '" << e.message() <<
"'. Restarting timer.";
1198 timer.expires_after(expiryTime);
1199 timer.async_wait(std::move(*optionalCountedHandler));
1210 jobQueue_.addJob(JtNetopTimer,
"NetHeart", [this]() { processHeartbeatTimer(); });
1212 [
this]() { setHeartbeatTimer(); });
1218 using namespace std::chrono_literals;
1232 JLOG(
journal_.debug()) <<
"Scheduling AccountHistory job for account "
1234 using namespace std::chrono_literals;
1262 ss <<
"Node count (" << numPeers <<
") has fallen "
1265 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
1269 CLOG(clog.
ss()) <<
"already DISCONNECTED. too few peers (" << numPeers
1285 JLOG(
journal_.info()) <<
"Node count (" << numPeers <<
") is sufficient.";
1286 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers <<
" peers. ";
1291 auto origMode =
mode_.load();
1301 auto newMode =
mode_.load();
1302 if (origMode != newMode)
1306 CLOG(clog.
ss()) <<
". ";
1319 CLOG(clog.
ss()) <<
". ";
1327 if (
registry_.get().getCluster().size() == 0)
1330 using namespace std::chrono_literals;
1332 bool const update =
registry_.get().getCluster().update(
1333 registry_.get().getApp().nodeIdentity().first,
1336 ?
registry_.get().getFeeTrack().getLocalFee()
1342 JLOG(
journal_.debug()) <<
"Too soon to send cluster update";
1347 protocol::TMCluster cluster;
1349 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1354 n.set_nodename(node.
name());
1358 for (
auto& item : gossip.
items)
1360 protocol::TMLoadSource& node = *cluster.add_loadsources();
1362 node.set_cost(item.balance);
1376 auto const consensusMode =
consensus_.mode();
1383 return "validating";
1403 JLOG(
journal_.error()) <<
"Submitted transaction invalid: tfInnerBatchTxn flag present.";
1410 auto const txid = trans->getTransactionID();
1411 auto const flags =
registry_.get().getHashRouter().getFlags(txid);
1415 JLOG(
journal_.warn()) <<
"Submitted transaction cached bad";
1426 JLOG(
journal_.warn()) <<
"Submitted transaction invalid: " << reason;
1432 JLOG(
journal_.warn()) <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1450 auto const newFlags =
registry_.get().getHashRouter().getFlags(transaction->getID());
1455 JLOG(
journal_.warn()) << transaction->getID() <<
": cached bad!\n";
1466 auto const sttx = *transaction->getSTransaction();
1486 auto const& viewRules = view->rules();
1492 JLOG(
journal_.info()) <<
"Transaction has bad signature: " << reason;
1498 if (viewRules.enabled(fixCleanup3_4_0) ||
1499 (!sttx.isFieldPresent(sfSponsorSignature) &&
1500 !sttx.isFieldPresent(sfCounterpartySignature)))
1508 registry_.get().getMasterTransaction().canonicalize(&transaction);
1544 if (transaction->getApplying())
1547 transactions_.emplace_back(transaction, bUnlimited,
false, failType);
1548 transaction->setApplying();
1552 if (
jobQueue_.addJob(
JtBatch,
"TxBatchAsync", [
this]() { transactionBatch(); }))
1567 if (!transaction->getApplying())
1569 transactions_.emplace_back(transaction, bUnlimited,
true, failType);
1570 transaction->setApplying();
1574 return transaction->getApplying();
1597 if (
jobQueue_.addJob(
JtBatch,
"TxBatchSync", [
this]() { transactionBatch(); }))
1603 }
while (retryCallback(lock));
1612 for (
auto const& [_, tx] :
set)
1619 if (!reason.
empty())
1621 JLOG(
journal_.trace()) <<
"Exception checking transaction: " << reason;
1639 for (
auto& transaction : candidates)
1641 if (!transaction->getApplying())
1644 transaction->setApplying();
1660 JLOG(
journal_.debug()) <<
"No transaction to process!";
1665 XRPL_ASSERT(lock.owns_lock(),
"xrpl::NetworkOPsImp::processTransactionSet has lock");
1667 transactions_, [](
auto const& t) {
return t.transaction->getApplying(); });
1691 XRPL_ASSERT(!
transactions.empty(),
"xrpl::NetworkOPsImp::apply : non-empty transactions");
1701 bool changed =
false;
1716 auto const result =
registry_.get().getTxQ().apply(
1717 registry_.get().getApp(), view, e.transaction->getSTransaction(), flags, j);
1718 e.result = result.ter;
1719 e.applied = result.applied;
1720 changed = changed || result.applied;
1730 validatedLedgerIndex = l->header().seq;
1732 auto newOL =
registry_.get().getOpenLedger().current();
1735 e.transaction->clearSubmitResult();
1740 e.transaction->setApplied();
1743 e.transaction->setResult(e.result);
1747 registry_.get().getHashRouter().setFlags(
1758 JLOG(
journal_.info()) <<
"TransactionResult: " << token <<
": " << human;
1763 bool const addLocal = e.local;
1767 JLOG(
journal_.debug()) <<
"Transaction is now included in open ledger";
1773 auto const& txCur = e.transaction->getSTransaction();
1785 if (t->getApplying())
1796 JLOG(
journal_.info()) <<
"Transaction is obsolete";
1801 JLOG(
journal_.debug()) <<
"Transaction is likely to claim a"
1802 <<
" fee, but is queued until fee drops";
1809 e.transaction->setQueued();
1810 e.transaction->setKept();
1816 auto const lastLedgerSeq =
1817 e.transaction->getSTransaction()->at(~sfLastLedgerSequence);
1818 auto const ledgersLeft = lastLedgerSeq
1838 registry_.get().getHashRouter().setFlags(
1842 JLOG(
journal_.debug()) <<
"Transaction should be held: " << e.result;
1845 e.transaction->setKept();
1850 <<
"Not holding transaction " << e.transaction->getID() <<
": "
1851 << (e.local ?
"local" :
"network") <<
", "
1852 <<
"result: " << e.result <<
" ledgers left: "
1853 << (ledgersLeft ?
to_string(*ledgersLeft) :
"unspecified");
1859 JLOG(
journal_.debug()) <<
"Status other than success " << e.result;
1865 if (addLocal && !enforceFailHard)
1868 ledgerMaster_.getCurrentLedgerIndex(), e.transaction->getSTransaction());
1869 e.transaction->setKept();
1878 registry_.get().getHashRouter().shouldRelay(e.transaction->getID());
1879 if (
auto const sttx = *(e.transaction->getSTransaction()); toSkip &&
1886 protocol::TMTransaction tx;
1890 tx.set_rawtransaction(s.
data(), s.
size());
1891 tx.set_status(protocol::tsCURRENT);
1892 tx.set_receivetimestamp(
1893 registry_.get().getTimeKeeper().now().time_since_epoch().count());
1896 registry_.get().getOverlay().relay(e.transaction->getID(), tx, *toSkip);
1897 e.transaction->setBroadcast();
1901 if (validatedLedgerIndex)
1903 auto maybeFeeAndSeq =
registry_.get().getTxQ().getTxRequiredFeeAndSeq(
1904 *newOL, e.transaction->getSTransaction());
1905 if (maybeFeeAndSeq.has_value())
1907 auto [fee, accountSeq, availableSeq] = *maybeFeeAndSeq;
1908 e.transaction->setCurrentLedgerState(
1909 *validatedLedgerIndex, fee, accountSeq, availableSeq);
1914 <<
"Unable to compute current ledger state for tx "
1915 << e.transaction->getID() <<
" in validated ledger "
1916 << *validatedLedgerIndex <<
": " <<
transToken(maybeFeeAndSeq.error());
1925 e.transaction->clearApplying();
1927 if (!submitHeld.
empty())
1936 for (
auto& e : submitHeld)
1962 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1965 XRPL_ASSERT(sleCur,
"xrpl::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1967 switch (sleCur->getType())
1970 if (!jvObjects.
isMember(jss::offers))
1976 case ltRIPPLE_STATE:
1977 if (!jvObjects.
isMember(jss::ripple_lines))
1982 jvObjects[jss::ripple_lines].
append(
1986 case ltACCOUNT_ROOT:
1991 "xrpl::NetworkOPsImp::getOwnerInfo : invalid "
1998 uNodeDir = sleNode->getFieldU64(sfIndexNext);
2003 XRPL_ASSERT(sleNode,
"xrpl::NetworkOPsImp::getOwnerInfo : read next page");
2005 }
while (uNodeDir != 0u);
2079 JLOG(
journal_.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
2086 UInt256 closedLedger = ourClosed->header().hash;
2087 UInt256 const prevClosedLedger = ourClosed->header().parentHash;
2088 JLOG(
journal_.trace()) <<
"OurClosed: " << closedLedger;
2089 JLOG(
journal_.trace()) <<
"PrevClosed: " << prevClosedLedger;
2094 auto& validations =
registry_.get().getValidations();
2099 peerCounts[closedLedger] = 0;
2101 peerCounts[closedLedger]++;
2103 for (
auto& peer : peerList)
2105 UInt256 const peerLedger = peer->getClosedLedgerHash();
2108 ++peerCounts[peerLedger];
2111 for (
auto const& it : peerCounts)
2112 JLOG(
journal_.debug()) <<
"L: " << it.first <<
" n=" << it.second;
2114 UInt256 const preferredLCL = validations.getPreferredLCL(
2119 bool switchLedgers = preferredLCL != closedLedger;
2121 closedLedger = preferredLCL;
2123 if (switchLedgers && (closedLedger == prevClosedLedger))
2126 JLOG(
journal_.info()) <<
"We won't switch to our own previous ledger";
2127 networkClosed = ourClosed->header().hash;
2128 switchLedgers =
false;
2132 networkClosed = closedLedger;
2138 auto consensus =
ledgerMaster_.getLedgerByHash(closedLedger);
2142 consensus =
registry_.get().getInboundLedgers().acquire(
2152 networkClosed = ourClosed->header().hash;
2156 JLOG(
journal_.warn()) <<
"We are not running on the consensus ledger";
2157 JLOG(
journal_.info()) <<
"Our LCL: " << ourClosed->header().hash <<
getJson({*ourClosed, {}});
2158 JLOG(
journal_.info()) <<
"Net LCL " << closedLedger;
2180 JLOG(
journal_.error()) <<
"JUMP last closed ledger to " << newLCL->header().hash;
2185 registry_.get().getTxQ().processClosedLedger(
registry_.get().getApp(), *newLCL,
true);
2192 auto retries =
localTX_->getTxSet();
2193 auto const lastVal =
registry_.get().getLedgerMaster().getValidatedLedger();
2220 protocol::TMStatusChange s;
2221 s.set_newevent(protocol::neSWITCHED_LEDGER);
2222 s.set_ledgerseq(newLCL->header().seq);
2223 s.set_networktime(
registry_.get().getTimeKeeper().now().time_since_epoch().count());
2224 s.set_ledgerhashprevious(
2225 newLCL->header().parentHash.begin(), newLCL->header().parentHash.size());
2226 s.set_ledgerhash(newLCL->header().hash.begin(), newLCL->header().hash.size());
2236 XRPL_ASSERT(networkClosed.
isNonZero(),
"xrpl::NetworkOPsImp::beginConsensus : nonzero input");
2238 auto closingInfo =
ledgerMaster_.getCurrentLedger()->header();
2240 JLOG(
journal_.info()) <<
"Consensus time for #" << closingInfo.seq <<
" with LCL "
2241 << closingInfo.parentHash;
2243 auto prevLedger =
ledgerMaster_.getLedgerByHash(closingInfo.parentHash);
2250 JLOG(
journal_.warn()) <<
"Don't have LCL, going to tracking";
2252 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
2255 CLOG(clog) <<
"beginConsensus no previous ledger. ";
2260 prevLedger->header().hash == closingInfo.parentHash,
2261 "xrpl::NetworkOPsImp::beginConsensus : prevLedger hash matches "
2264 closingInfo.parentHash ==
ledgerMaster_.getClosedLedger()->header().hash,
2265 "xrpl::NetworkOPsImp::beginConsensus : closedLedger parent matches "
2268 registry_.get().getValidators().setNegativeUNL(prevLedger->negativeUNL());
2270 registry_.get().getValidations().getCurrentNodeIDs(),
2271 closingInfo.parentCloseTime,
2276 if (!changes.
added.empty() || !changes.
removed.empty())
2280 registry_.get().getAmendmentTable().trustChanged(
2281 registry_.get().getValidators().getQuorumKeys().second);
2285 registry_.get().getTimeKeeper().closeTime(),
2299 JLOG(
journal_.debug()) <<
"Initiating consensus engine";
2306 auto const& peerKey = peerPos.
publicKey();
2318 JLOG(
journal_.error()) <<
"Received a proposal signed by MY KEY from a peer. This may "
2319 "indicate a misconfiguration where another node has the same "
2320 "validator key, or may be caused by unusual message routing and "
2333 protocol::TMHaveTransactionSet msg;
2334 msg.set_hash(map->getHash().asUInt256().begin(), 256 / 8);
2335 msg.set_status(protocol::tsHAVE);
2348 for (
auto const& it :
registry_.get().getOverlay().getActivePeers())
2350 if (it && (it->getClosedLedgerHash() == deadLedger))
2352 JLOG(
journal_.trace()) <<
"Killing obsolete peer status";
2358 bool const ledgerChange =
2361 if (networkClosed.
isZero())
2363 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
2389 if (
registry_.get().getTimeKeeper().now() <
2390 (current->header().parentCloseTime + 2 * current->header().closeTimeResolution))
2424 jvObj[jss::type] =
"manifestReceived";
2430 jvObj[jss::signature] =
strHex(*sig);
2433 jvObj[jss::domain] = mo.
domain;
2438 if (
auto p = i->second.lock())
2440 p->send(jvObj,
true);
2459 ,
em{escalationMetrics}
2473 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2474 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2475 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2509 registry_.get().getOpenLedger().current()->fees().base,
2513 jvObj[jss::type] =
"serverStatus";
2526 jvObj[jss::load_factor] =
trunc32(loadFactor);
2527 jvObj[jss::load_factor_fee_escalation] = f.
em->openLedgerFeeLevel.jsonClipped();
2528 jvObj[jss::load_factor_fee_queue] = f.
em->minProcessingFeeLevel.jsonClipped();
2529 jvObj[jss::load_factor_fee_reference] = f.
em->referenceFeeLevel.jsonClipped();
2547 p->send(jvObj,
true);
2570 if (!streamMap.empty())
2573 jvObj[jss::type] =
"consensusPhase";
2574 jvObj[jss::consensus] =
to_string(phase);
2576 for (
auto i = streamMap.begin(); i != streamMap.end();)
2578 if (
auto p = i->second.lock())
2580 p->send(jvObj,
true);
2586 i = streamMap.erase(i);
2607 auto const signerPublic = val->getSignerPublic();
2609 jvObj[jss::type] =
"validationReceived";
2611 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2612 jvObj[jss::signature] =
strHex(val->getSignature());
2613 jvObj[jss::full] = val->isFull();
2614 jvObj[jss::flags] = val->getFlags();
2615 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2616 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2617 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
2619 if (
auto version = (*val)[~sfServerVersion])
2622 if (
auto cookie = (*val)[~sfCookie])
2625 if (
auto hash = (*val)[~sfValidatedHash])
2626 jvObj[jss::validated_hash] =
strHex(*hash);
2628 auto const masterKey =
registry_.get().getValidatorManifests().getMasterKey(signerPublic);
2630 if (masterKey != signerPublic)
2635 if (
auto const seq = (*val)[~sfLedgerSequence])
2636 jvObj[jss::ledger_index] = *seq;
2638 if (val->isFieldPresent(sfAmendments))
2641 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2645 if (
auto const closeTime = (*val)[~sfCloseTime])
2646 jvObj[jss::close_time] = *closeTime;
2648 if (
auto const loadFee = (*val)[~sfLoadFee])
2649 jvObj[jss::load_fee] = *loadFee;
2651 if (
auto const baseFee = val->at(~sfBaseFee))
2652 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2654 if (
auto const reserveBase = val->at(~sfReserveBase))
2655 jvObj[jss::reserve_base] = *reserveBase;
2657 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2658 jvObj[jss::reserve_inc] = *reserveInc;
2662 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); baseFeeXRP && baseFeeXRP->native())
2663 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2665 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
2666 reserveBaseXRP && reserveBaseXRP->native())
2667 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2669 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
2670 reserveIncXRP && reserveIncXRP->native())
2671 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2680 if (jvTx.
isMember(jss::ledger_index))
2682 jvTx[jss::ledger_index] =
std::to_string(jvTx[jss::ledger_index].asUInt());
2688 if (
auto p = i->second.lock())
2692 [&](
json::Value const& jv) { p->send(jv, true); });
2718 jvObj[jss::type] =
"peerStatusChange";
2726 p->send(jvObj,
true);
2741 using namespace std::chrono_literals;
2744 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() < 1min)
2749 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() >= 1min)
2770 JLOG(
journal_.trace()) <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2789 JLOG(
journal_.warn()) <<
"Exception thrown for handling new validation "
2790 << val->getLedgerHash() <<
": " << e.
what();
2794 JLOG(
journal_.warn()) <<
"Unknown exception thrown for handling new validation "
2795 << val->getLedgerHash();
2805 JLOG(
journal_.debug()) << [
this, &val]() ->
auto {
2807 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2808 auto master =
registry_.get().getValidators().getTrustedKey(val->getSignerPublic());
2822 return registry_.get().getApp().config().relayUntrustedValidations == 1 || val->isTrusted();
2844 "This server is amendment blocked, and must be updated to be "
2845 "able to stay in sync with the network.";
2852 "This server has an expired validator list. validators.txt "
2853 "may be incorrectly configured or some [validator_list_sites] "
2854 "may be unreachable.";
2861 "One or more unsupported amendments have reached majority. "
2862 "Upgrade to the latest version before they are activated "
2863 "to avoid being amendment blocked.";
2864 if (
auto const expected =
2865 registry_.get().getAmendmentTable().firstUnsupportedExpected())
2868 d[jss::expected_date] = expected->time_since_epoch().count();
2869 d[jss::expected_date_UTC] =
to_string(*expected);
2873 if (warnings.
size() != 0u)
2874 info[jss::warnings] = std::move(warnings);
2882 if (!
registry_.get().getApp().config().serverDomain.empty())
2883 info[jss::server_domain] =
registry_.get().getApp().config().serverDomain;
2893 info[jss::network_ledger] =
"waiting";
2895 info[jss::validation_quorum] =
2903 switch (
registry_.get().getApp().config().nodeSize)
2906 info[jss::node_size] =
"tiny";
2909 info[jss::node_size] =
"small";
2912 info[jss::node_size] =
"medium";
2915 info[jss::node_size] =
"large";
2918 info[jss::node_size] =
"huge";
2922 auto when =
registry_.get().getValidators().expires();
2928 info[jss::validator_list_expires] =
2933 info[jss::validator_list_expires] = 0;
2944 if (*when == TimeKeeper::time_point::max())
2946 x[jss::expiration] =
"never";
2947 x[jss::status] =
"active";
2953 if (*when >
registry_.get().getTimeKeeper().now())
2955 x[jss::status] =
"active";
2959 x[jss::status] =
"expired";
2965 x[jss::status] =
"unknown";
2966 x[jss::expiration] =
"unknown";
2979 info[jss::io_latency_ms] =
2984 if (
auto const localPubKey =
registry_.get().getValidators().localPublicKey();
2985 localPubKey &&
registry_.get().getApp().getValidationPublicKey())
2991 info[jss::pubkey_validator] =
"none";
2997 info[jss::counters] =
registry_.get().getPerfLog().countersJson();
3000 registry_.get().getNodeStore().getCountsJson(nodestore);
3001 info[jss::counters][jss::nodestore] = nodestore;
3002 info[jss::current_activities] =
registry_.get().getPerfLog().currentJson();
3005 info[jss::pubkey_node] =
3008 info[jss::complete_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
3011 info[jss::amendment_blocked] =
true;
3025 lastClose[jss::converge_time_s] =
3033 info[jss::last_close] = lastClose;
3040 if (
auto const netid =
registry_.get().getOverlay().networkID())
3041 info[jss::network_id] =
static_cast<json::UInt>(*netid);
3043 auto const escalationMetrics =
3046 auto const loadFactorServer =
registry_.get().getFeeTrack().getLoadFactor();
3047 auto const loadBaseServer =
registry_.get().getFeeTrack().getLoadBase();
3051 auto const loadFactorFeeEscalation =
mulDiv(
3052 escalationMetrics.openLedgerFeeLevel,
3054 escalationMetrics.referenceFeeLevel)
3057 auto const loadFactor =
3062 info[jss::load_base] = loadBaseServer;
3063 info[jss::load_factor] =
trunc32(loadFactor);
3064 info[jss::load_factor_server] = loadFactorServer;
3071 info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.jsonClipped();
3072 info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.jsonClipped();
3073 info[jss::load_factor_fee_reference] = escalationMetrics.referenceFeeLevel.jsonClipped();
3077 info[jss::load_factor] =
static_cast<double>(loadFactor) / loadBaseServer;
3079 if (loadFactorServer != loadFactor)
3080 info[jss::load_factor_server] =
static_cast<double>(loadFactorServer) / loadBaseServer;
3085 if (fee != loadBaseServer)
3086 info[jss::load_factor_local] =
static_cast<double>(fee) / loadBaseServer;
3087 fee =
registry_.get().getFeeTrack().getRemoteFee();
3088 if (fee != loadBaseServer)
3089 info[jss::load_factor_net] =
static_cast<double>(fee) / loadBaseServer;
3090 fee =
registry_.get().getFeeTrack().getClusterFee();
3091 if (fee != loadBaseServer)
3092 info[jss::load_factor_cluster] =
static_cast<double>(fee) / loadBaseServer;
3094 if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel &&
3095 (admin || loadFactorFeeEscalation != loadFactor))
3097 info[jss::load_factor_fee_escalation] =
3098 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
3099 escalationMetrics.referenceFeeLevel);
3101 if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel)
3103 info[jss::load_factor_fee_queue] =
3104 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
3105 escalationMetrics.referenceFeeLevel);
3123 XRPAmount const baseFee = lpClosed->fees().base;
3125 l[jss::seq] =
json::UInt(lpClosed->header().seq);
3126 l[jss::hash] =
to_string(lpClosed->header().hash);
3131 l[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
3132 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
3133 l[jss::close_time] =
3139 l[jss::reserve_base_xrp] = lpClosed->fees().reserve.decimalXRP();
3140 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
3142 if (
auto const closeOffset =
registry_.get().getTimeKeeper().closeOffset();
3143 std::abs(closeOffset.count()) >= 60)
3144 l[jss::close_time_offset] =
static_cast<std::uint32_t>(closeOffset.count());
3154 auto lCloseTime = lpClosed->header().closeTime;
3155 auto closeTime =
registry_.get().getTimeKeeper().closeTime();
3156 if (lCloseTime <= closeTime)
3158 using namespace std::chrono_literals;
3159 auto age = closeTime - lCloseTime;
3167 info[jss::validated_ledger] = l;
3171 info[jss::closed_ledger] = l;
3177 info[jss::published_ledger] =
"none";
3179 else if (lpPublished->header().seq != lpClosed->header().seq)
3181 info[jss::published_ledger] = lpPublished->header().seq;
3187 info[jss::jq_trans_overflow] =
3190 info[jss::peer_disconnects_resources] =
3195 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
3199 for (
auto const& port :
registry_.get().getServerHandler().setup().ports)
3203 !(port.adminNetsV4.empty() && port.adminNetsV6.empty() && port.adminUser.empty() &&
3204 port.adminPassword.empty()))
3219 for (
auto const& p : proto)
3220 jv[jss::protocol].
append(p);
3226 auto const& grpcSection =
3228 auto const optPort = grpcSection.get(
Keys::kPort);
3229 if (optPort && grpcSection.get(
Keys::kIp))
3232 jv[jss::port] = *optPort;
3234 jv[jss::protocol].
append(
"grpc");
3237 info[jss::ports] = std::move(ports);
3246 registry_.get().getInboundLedgers().clearFailures();
3252 return registry_.get().getInboundLedgers().getInfo();
3288 [&](
json::Value const& jv) { p->send(jv, true); });
3309 registry_.get().getAcceptedLedgerCache().fetch(lpAccepted->header().hash);
3313 registry_.get().getAcceptedLedgerCache().canonicalizeReplaceClient(
3314 lpAccepted->header().hash, alpAccepted);
3318 alpAccepted->getLedger().get() == lpAccepted.
get(),
3319 "xrpl::NetworkOPsImp::pubLedger : accepted input");
3321 JLOG(
journal_.debug()) <<
"Publishing ledger " << lpAccepted->header().seq <<
" "
3322 << lpAccepted->header().hash;
3331 for (
auto const& accTx : *alpAccepted)
3333 JLOG(
journal_.trace()) <<
"pubAccepted: " << accTx->getJson();
3334 bool const last = &*accTx == &alpAccepted->back();
3356 jvObj[jss::type] =
"ledgerClosed";
3357 jvObj[jss::ledger_index] = lpAccepted->header().seq;
3358 jvObj[jss::ledger_hash] =
to_string(lpAccepted->header().hash);
3359 jvObj[jss::ledger_time] =
3362 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
3364 if (!lpAccepted->rules().enabled(featureXRPFees))
3366 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
3367 jvObj[jss::reserve_base] = lpAccepted->fees().reserve.jsonClipped();
3368 jvObj[jss::reserve_inc] = lpAccepted->fees().increment.jsonClipped();
3370 jvObj[jss::txn_count] =
json::UInt(alpAccepted->size());
3374 jvObj[jss::validated_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
3382 p->send(jvObj,
true);
3403 p->send(jvObj,
true);
3430 for (
auto& inner : outer.second)
3432 auto& subInfo = inner.second;
3433 if (subInfo.index->separationLedgerSeq == 0)
3443 registry_.get().getOpenLedger().current()->fees().base,
3476 for (
auto const& [_, subs] :
subBook_)
3477 total += subs.size();
3497 jvObj[jss::type] =
"transaction";
3510 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
3511 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
3513 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
3514 uint32_t netID =
registry_.get().getNetworkIDService().getNetworkID();
3515 if (transaction->isFieldPresent(sfNetworkID))
3516 netID = transaction->getFieldU32(sfNetworkID);
3520 jvObj[jss::ctid] = *ctid;
3522 if (!ledger->open())
3523 jvObj[jss::ledger_hash] =
to_string(ledger->header().hash);
3527 jvObj[jss::ledger_index] = ledger->header().seq;
3528 jvObj[jss::transaction][jss::date] = ledger->header().closeTime.time_since_epoch().count();
3529 jvObj[jss::validated] =
true;
3530 jvObj[jss::close_time_iso] =
toStringIso(ledger->header().closeTime);
3536 jvObj[jss::validated] =
false;
3537 jvObj[jss::ledger_current_index] = ledger->header().seq;
3540 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3541 jvObj[jss::engine_result] = sToken;
3542 jvObj[jss::engine_result_code] = result;
3543 jvObj[jss::engine_result_message] = sHuman;
3545 if (transaction->getTxnType() == ttOFFER_CREATE)
3547 auto const account = transaction->getAccountID(sfAccount);
3548 auto const amount = transaction->getFieldAmount(sfTakerGets);
3551 if (account != amount.getIssuer())
3560 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3569 rpc::insertDeliverMax(jvTx[jss::transaction], transaction->getTxnType(), Version);
3571 if constexpr (Version > 1)
3573 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3574 jvTx[jss::hash] = hash;
3578 jvTx[jss::transaction][jss::hash] = hash;
3591 auto const& stTxn = transaction.
getTxn();
3595 auto const trResult = transaction.
getResult();
3616 [&](
json::Value const& jv) { p->send(jv, true); });
3636 [&](
json::Value const& jv) { p->send(jv, true); });
3686 listeners.
reserve(books.size());
3692 for (
auto const& book : books)
3698 for (
auto sit = it->second.begin(); sit != it->second.end();)
3700 if (
auto p = sit->second.lock())
3707 if (seen.
emplace(p->getSeq()).second)
3714 <<
"pubBookTransaction: pruning expired weak_ptr for seq=" << sit->first;
3715 sit = it->second.erase(sit);
3719 if (it->second.empty())
3724 for (
auto const& p : listeners)
3726 jvObj.
visit(p->getApiVersion(), [&](
json::Value const& jv) { p->send(jv, true); });
3743 auto const currLedgerSeq = ledger->seq();
3749 for (
auto const& affectedAccount : transaction.
getAffected())
3754 auto it = simiIt->second.begin();
3756 while (it != simiIt->second.end())
3768 it = simiIt->second.erase(it);
3775 auto it = simiIt->second.begin();
3776 while (it != simiIt->second.end())
3788 it = simiIt->second.erase(it);
3796 auto& subs = historyIt->second;
3797 auto it = subs.begin();
3798 while (it != subs.end())
3801 if (currLedgerSeq <= info.index->separationLedgerSeq)
3815 it = subs.erase(it);
3825 JLOG(
journal_.trace()) <<
"pubAccountTransaction: "
3826 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3828 if (!notify.
empty() || !accountHistoryNotify.
empty())
3830 auto const& stTxn = transaction.
getTxn();
3834 auto const trResult = transaction.
getResult();
3840 isrListener->getApiVersion(),
3841 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3845 jvObj.
set(jss::account_history_boundary,
true);
3848 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3849 "xrpl::NetworkOPsImp::pubAccountTransaction : "
3850 "account_history_tx_stream not set");
3851 for (
auto& info : accountHistoryNotify)
3853 auto& index = info.index;
3854 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3855 jvObj.
set(jss::account_history_tx_first,
true);
3857 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3860 info.sink->getApiVersion(),
3861 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3885 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3890 auto it = simiIt->second.begin();
3892 while (it != simiIt->second.end())
3904 it = simiIt->second.erase(it);
3912 JLOG(
journal_.trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3914 if (!notify.
empty() || !accountHistoryNotify.
empty())
3922 isrListener->getApiVersion(),
3923 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3927 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3928 "xrpl::NetworkOPs::pubProposedAccountTransaction : "
3929 "account_history_tx_stream not set");
3930 for (
auto& info : accountHistoryNotify)
3932 auto& index = info.index;
3933 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3934 jvObj.
set(jss::account_history_tx_first,
true);
3935 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3937 info.sink->getApiVersion(),
3938 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3955 for (
auto const& naAccountID : vnaAccountIDs)
3957 JLOG(
journal_.trace()) <<
"subAccount: account: " <<
toBase58(naAccountID);
3959 isrListener->insertSubAccountInfo(naAccountID, rt);
3964 for (
auto const& naAccountID : vnaAccountIDs)
3966 auto simIterator = subMap.
find(naAccountID);
3967 if (simIterator == subMap.
end())
3971 usisElement[isrListener->getSeq()] = isrListener;
3973 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3978 simIterator->second[isrListener->getSeq()] = isrListener;
3989 for (
auto const& naAccountID : vnaAccountIDs)
3992 isrListener->deleteSubAccountInfo(naAccountID, rt);
4009 for (
auto const& naAccountID : vnaAccountIDs)
4011 auto simIterator = subMap.
find(naAccountID);
4013 if (simIterator != subMap.
end())
4016 simIterator->second.erase(uSeq);
4018 if (simIterator->second.empty())
4021 subMap.
erase(simIterator);
4027template <
typename OuterMap,
typename BeforeErase>
4033 BeforeErase&& beforeErase)
4040 auto it = accounts.
begin();
4041 auto const end = accounts.
end();
4048 auto outerIter = outerMap.find(*it);
4049 if (outerIter != outerMap.end())
4054 auto innerIter = outerIter->second.find(seq);
4055 if (innerIter != outerIter->second.end())
4056 beforeErase(innerIter->second);
4060 outerIter->second.erase(seq);
4061 if (outerIter->second.empty())
4062 outerMap.erase(outerIter);
4089 info.
index->stopHistorical =
true;
4101 if (rtAccounts.
empty() && normalAccounts.
empty() && historyAccounts.
empty())
4123 rt = std::move(rtAccounts),
4124 normal = std::move(normalAccounts),
4125 history = std::move(historyAccounts)]()
noexcept {
4134 JLOG(
journal_.error()) <<
"SubCleanup[seq=" << seq <<
"]: " << e.
what();
4138 JLOG(
journal_.error()) <<
"SubCleanup[seq=" << seq <<
"]: unknown exception";
4157 if (affectedMPTs.empty())
4167 for (
auto const& affectedMPT : affectedMPTs)
4169 if (
auto simiIt =
subMPT_.find(affectedMPT); simiIt !=
subMPT_.end())
4171 auto it = simiIt->second.begin();
4172 while (it != simiIt->second.end())
4183 it = simiIt->second.erase(it);
4196 jvMPT.
set(jss::type,
"mptTransaction");
4201 isrListener->send(jv, true);
4215 for (
auto const& mptID : mptIDs)
4219 auto simIterator =
subMPT_.find(mptID);
4220 if (simIterator ==
subMPT_.end())
4224 usisElement[isrListener->getSeq()] = isrListener;
4225 subMPT_.insert(simIterator, make_pair(mptID, usisElement));
4230 simIterator->second[isrListener->getSeq()] = isrListener;
4235 for (
auto const& mptID : mptIDs)
4236 isrListener->insertSubMPTInfo(mptID);
4242 for (
auto const& mptID : mptIDs)
4247 isrListener->deleteSubMPTInfo(mptID);
4258 auto simIterator =
subMPT_.find(mptID);
4259 if (simIterator ==
subMPT_.end())
4262 simIterator->second.erase(uSeq);
4263 if (simIterator->second.empty())
4274 auto const& accountId = subInfo.
index->accountId;
4275 auto& lastLedgerSeq = subInfo.
index->historyLastLedgerSeq;
4276 auto& txHistoryIndex = subInfo.
index->historyTxIndex;
4278 JLOG(
journal_.trace()) <<
"AccountHistory job for account " <<
toBase58(accountId)
4279 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
4289 auto stx = tx->getSTransaction();
4290 if (stx->getAccountID(sfAccount) == accountId && stx->getSeqProxy().value() == 1)
4295 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
4298 if (node.isFieldPresent(sfNewFields))
4300 if (auto inner = dynamic_cast<STObject const*>(node.peekAtPField(sfNewFields));
4303 if (inner->isFieldPresent(sfAccount) &&
4304 inner->getAccountID(sfAccount) == accountId)
4314 auto send = [&](
json::Value const& jvObj,
bool unsubscribe) ->
bool {
4317 sptr->send(jvObj,
true);
4326 auto sendMultiApiJson = [&](
MultiApiJson const& jvObj,
bool unsubscribe) ->
bool {
4330 sptr->getApiVersion(),
4331 [&](
json::Value const& jv) { sptr->send(jv, true); });
4347 auto& db =
registry_.get().getRelationalDatabase();
4349 .account = accountId,
4350 .ledgerRange = {.min = minLedger, .max = maxLedger},
4354 .delegate = std::nullopt};
4355 return db.newestAccountTxPage(options);
4361 while (lastLedgerSeq >= 2 && !subInfo.
index->stopHistorical)
4363 int feeChargeCount = 0;
4364 if (auto sptr = subInfo.sinkWptr.lock(); sptr)
4366 sptr->getConsumer().charge(resource::kFeeMediumBurdenRpc);
4371 JLOG(journal_.trace())
4372 <<
"AccountHistory job for account " << toBase58(accountId)
4373 <<
" no InfoSub. Fee charged " << feeChargeCount <<
" times.";
4378 auto startLedgerSeq = (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
4380 <<
"AccountHistory job for account " <<
toBase58(accountId)
4381 <<
", working on ledger range [" << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
4383 auto haveRange = [&]() ->
bool {
4386 auto haveSomeValidatedLedgers =
4387 registry_.get().getLedgerMaster().getValidatedRange(validatedMin, validatedMax);
4389 return haveSomeValidatedLedgers && validatedMin <= startLedgerSeq &&
4390 lastLedgerSeq <= validatedMax;
4395 JLOG(
journal_.debug()) <<
"AccountHistory reschedule job for account "
4396 <<
toBase58(accountId) <<
", incomplete ledger range ["
4397 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
4403 while (!subInfo.
index->stopHistorical)
4405 auto dbResult = getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
4407 auto const& txns = dbResult.first;
4408 marker = dbResult.second;
4409 size_t const numTxns = txns.size();
4410 for (size_t i = 0; i < numTxns; ++i)
4412 auto const& [tx, meta] = txns[i];
4416 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4417 << toBase58(accountId) <<
" empty tx or meta.";
4418 send(rpcError(RpcInternal), true);
4422 registry_.get().getLedgerMaster().getLedgerBySeq(tx->getLedger());
4427 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
4428 "getLedgerBySeq failed");
4429 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4430 << toBase58(accountId) <<
" no ledger.";
4431 send(rpcError(RpcInternal), true);
4435 std::shared_ptr<STTx const> const stTxn = tx->getSTransaction();
4440 "NetworkOPsImp::addAccountHistoryJob : "
4441 "getSTransaction failed");
4442 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4443 << toBase58(accountId) <<
" getSTransaction failed.";
4444 send(rpcError(RpcInternal), true);
4449 auto const ref = std::ref(*meta);
4450 auto const trR = meta->getResultTER();
4451 MultiApiJson jvTx = transJson(stTxn, trR, true, curTxLedger, ref);
4453 jvTx.set(jss::account_history_tx_index, txHistoryIndex--);
4454 if (i + 1 == numTxns || txns[i + 1].first->getLedger() != tx->getLedger())
4455 jvTx.set(jss::account_history_boundary, true);
4457 if (isFirstTx(tx, meta))
4459 jvTx.set(jss::account_history_tx_first, true);
4460 sendMultiApiJson(jvTx, false);
4462 JLOG(journal_.trace()) <<
"AccountHistory job for account "
4463 << toBase58(accountId) <<
" done, found last tx.";
4467 sendMultiApiJson(jvTx, false);
4473 <<
"AccountHistory job for account " <<
toBase58(accountId)
4474 <<
" paging, marker=" << marker->ledgerSeq <<
":" << marker->txnSeq;
4482 if (!subInfo.index->stopHistorical)
4484 lastLedgerSeq = startLedgerSeq - 1;
4485 if (lastLedgerSeq <= 1)
4487 JLOG(journal_.trace())
4488 <<
"AccountHistory job for account " << toBase58(accountId)
4489 <<
" done, reached genesis ledger.";
4502 subInfo.
index->separationLedgerSeq = ledger->seq();
4503 auto const& accountId = subInfo.
index->accountId;
4505 if (!ledger->exists(accountKeylet))
4507 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
4508 <<
", no need to add AccountHistory job.";
4513 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
4515 if (sleAcct->getFieldU32(sfSequence) == 1)
4518 <<
"subAccountHistoryStart, genesis account " <<
toBase58(accountId)
4519 <<
" does not have tx, no need to add AccountHistory job.";
4527 "xrpl::NetworkOPsImp::subAccountHistoryStart : failed to "
4528 "access genesis account");
4533 subInfo.
index->historyLastLedgerSeq = ledger->seq();
4534 subInfo.
index->haveHistorical =
true;
4536 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, add AccountHistory job: accountId="
4537 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
4545 if (!isrListener->insertSubAccountHistory(accountId))
4547 JLOG(
journal_.debug()) <<
"subAccountHistory, already subscribed to account "
4559 inner.
emplace(isrListener->getSeq(), ahi);
4564 simIterator->second.emplace(isrListener->getSeq(), ahi);
4567 auto const ledger =
registry_.get().getLedgerMaster().getValidatedLedger();
4577 JLOG(
journal_.debug()) <<
"subAccountHistory, no validated ledger yet, delay start";
4590 isrListener->deleteSubAccountHistory(account);
4604 auto& subInfoMap = simIterator->second;
4605 auto subInfoIter = subInfoMap.find(seq);
4606 if (subInfoIter != subInfoMap.end())
4608 subInfoIter->second.index->stopHistorical =
true;
4613 simIterator->second.erase(seq);
4614 if (simIterator->second.empty())
4619 JLOG(
journal_.debug()) <<
"unsubAccountHistory, account " <<
toBase58(account)
4620 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
4633 subBook_[book].try_emplace(isrListener->getSeq(), isrListener);
4635 isrListener->insertBookSubscription(book);
4645 isrListener->deleteBookSubscription(book);
4656 bool const erased = it->second.erase(uSeq) != 0u;
4657 if (it->second.empty())
4667 XRPL_ASSERT(
standalone_,
"xrpl::NetworkOPsImp::acceptLedger : is standalone");
4685 jvResult[jss::ledger_index] = lpClosed->header().seq;
4686 jvResult[jss::ledger_hash] =
to_string(lpClosed->header().hash);
4687 jvResult[jss::ledger_time] =
4689 if (!lpClosed->rules().enabled(featureXRPFees))
4691 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
4692 jvResult[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
4693 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
4694 jvResult[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
4699 jvResult[jss::validated_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
4758 auto const& feeTrack =
registry_.get().getFeeTrack();
4759 jvResult[jss::random] =
to_string(uRandom);
4761 jvResult[jss::load_base] = feeTrack.getLoadBase();
4762 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4763 jvResult[jss::hostid] =
getHostId(admin);
4764 jvResult[jss::pubkey_node] =
4916 if (map.contains(pInfo->getSeq()))
4925#ifndef USE_NEW_BOOK_PAGE
4936 unsigned int iLimit,
4945 UInt256 uTipIndex = uBookBase;
4947 if (
auto stream =
journal_.trace())
4949 stream <<
"getBookPage:" << book;
4950 stream <<
"getBookPage: uBookBase=" << uBookBase;
4951 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4952 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4960 bool bDirectAdvance =
true;
4964 unsigned int uBookEntry = 0;
4968 auto viewJ =
registry_.get().getJournal(
"View");
4970 while (!bDone && iLimit-- > 0)
4974 bDirectAdvance =
false;
4976 JLOG(
journal_.trace()) <<
"getBookPage: bDirectAdvance";
4978 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4985 sleOfferDir.
reset();
4990 JLOG(
journal_.trace()) <<
"getBookPage: bDone";
4995 uTipIndex = sleOfferDir->key();
4998 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
5000 JLOG(
journal_.trace()) <<
"getBookPage: uTipIndex=" << uTipIndex;
5001 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
5011 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
5012 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
5013 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
5015 bool firstOwnerOffer(
true);
5016 auto foundBalance = [&]() {
5017 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
5018 if (umBalanceEntry == umBalance.
end())
5022 saOwnerFunds = umBalanceEntry->second;
5023 firstOwnerOffer =
false;
5027 if (book.out.getIssuer() == uOfferOwnerID)
5033 saOwnerFunds = saTakerGets;
5040 if (!foundBalance())
5048 else if (bGlobalFreeze)
5052 saOwnerFunds.
clear(book.out);
5056 if (!foundBalance())
5072 saOwnerFunds.
clear();
5080 STAmount saOwnerFundsLimit = saOwnerFunds;
5085 && uTakerID != book.out.getIssuer()
5087 && book.out.getIssuer() != uOfferOwnerID)
5112 saOwnerFunds.
asset())
5113 :
divide(saOwnerFunds, offerRate);
5116 if (saOwnerFundsLimit >= saTakerGets)
5119 saTakerGetsFunded = saTakerGets;
5125 saTakerGetsFunded = saOwnerFundsLimit;
5127 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
5129 saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.
asset()))
5130 .setJson(jvOffer[jss::taker_pays_funded]);
5139 auto const grossed = [&]() {
5143 saTakerGetsFunded.
mpt(),
5149 [&](
Issue const&) {
return multiply(saTakerGetsFunded, offerRate); });
5153 :
std::min(saOwnerFunds, grossed());
5155 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
5159 jvOf[jss::quality] = saDirRate.
getText();
5161 if (firstOwnerOffer)
5162 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
5166 JLOG(
journal_.warn()) <<
"Missing offer";
5169 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
5171 bDirectAdvance =
true;
5175 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
5197 unsigned int iLimit,
5205 MetaView lesActive(lpLedger, tapNONE,
true);
5206 OrderBookIterator obIterator(lesActive, book);
5208 auto const rate =
transferRate(lesActive, book.out.account);
5210 bool const bGlobalFreeze =
5211 lesActive.isGlobalFrozen(book.out.account) || lesActive.isGlobalFrozen(book.in.account);
5213 while (iLimit-- > 0 && obIterator.nextOffer())
5218 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
5219 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
5220 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
5221 STAmount saDirRate = obIterator.getCurrentRate();
5224 if (book.out.account == uOfferOwnerID)
5227 saOwnerFunds = saTakerGets;
5229 else if (bGlobalFreeze)
5233 saOwnerFunds.
clear(book.out);
5237 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
5239 if (umBalanceEntry != umBalance.
end())
5243 saOwnerFunds = umBalanceEntry->second;
5249 saOwnerFunds = lesActive.accountHolds(
5255 if (saOwnerFunds.isNegative())
5259 saOwnerFunds.zero();
5266 STAmount saTakerGetsFunded;
5267 STAmount saOwnerFundsLimit = saOwnerFunds;
5268 Rate offerRate = parityRate;
5270 if (rate != parityRate
5272 && uTakerID !=
book.out.account
5274 &&
book.out.account != uOfferOwnerID)
5279 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
5282 if (saOwnerFundsLimit >= saTakerGets)
5285 saTakerGetsFunded = saTakerGets;
5290 saTakerGetsFunded = saOwnerFundsLimit;
5292 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
5296 std::min(saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.asset()))
5297 .setJson(jvOffer[jss::taker_pays_funded]);
5300 STAmount saOwnerPays = (parityRate == offerRate)
5302 : std::
min(saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
5304 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
5306 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
5309 json::Value& jvOf = jvOffers.append(jvOffer);
5310 jvOf[jss::quality] = saDirRate.getText();
5324 auto [counters, mode, start, initialSync] =
accounting_.getCounterData();
5327 counters[
static_cast<std::size_t>(mode)].dur += current;
5330 stats_.disconnectedDuration.set(
5332 stats_.connectedDuration.set(
5334 stats_.syncingDuration.set(
5336 stats_.trackingDuration.set(
5340 stats_.disconnectedTransitions.set(
5342 stats_.connectedTransitions.set(
5344 stats_.syncingTransitions.set(
5346 stats_.trackingTransitions.set(
5384 auto& state = obj[jss::state_accounting][
kStates[i]];
5385 state[jss::transitions] =
std::to_string(counters[i].transitions);
5386 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
5388 obj[jss::server_state_duration_us] =
std::to_string(current.count());
5389 if (initialSync != 0u)
5390 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
5405 boost::asio::io_context& ioCtx,
T back_inserter(T... args)
A generic endpoint for log messages.
std::shared_ptr< Collector > Ptr
A metric for measuring an integral value.
A reference to a handler for performing polled collection.
Decorator for streaming out compact json.
Lightweight wrapper to tag static string.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
bool isMember(char const *key) const
Return true if the object has a member named key.
A transaction that is in a closed ledger.
TxMeta const & getMeta() const
boost::container::flat_set< AccountID > const & getAffected() const
std::shared_ptr< STTx const > const & getTxn() const
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
static constexpr std::size_t size()
Holds transactions which were deferred to the next pass of consensus.
The role of a ClosureCounter is to assist in shutdown by letting callers wait for the completion of c...
std::uint32_t getLoadFee() const
NetClock::time_point getReportTime() const
PublicKey const & identity() const
std::string const & name() const
std::shared_ptr< InfoSub > const & Ref
std::shared_ptr< InfoSub > pointer
std::weak_ptr< InfoSub > Wptr
A currency issued by an account.
A pool of threads to perform work.
Tracks the current ledger and any ledgers in the process of closing.
Manages the current fee schedule.
void heartbeat()
Reset the stall detection timer.
static constexpr int kHoldLedgers
State accounting records two attributes for each possible server state: 1) Amount of time spent in ea...
void json(json::Value &obj) const
Output state counters in JSON format.
std::chrono::steady_clock::time_point const processStart_
CounterData getCounterData() const
std::uint64_t initialSyncUs_
static std::array< json::StaticString const, 5 > const kStates
std::array< Counters, 5 > counters_
void mode(OperatingMode om)
Record state transition.
std::chrono::steady_clock::time_point start_
Transaction with input flags and results to be applied in batches.
std::shared_ptr< Transaction > const transaction
TransactionStatus(std::shared_ptr< Transaction > t, bool a, bool l, FailHard f)
SubBookMapType subBook_
Guarded by bookLock_.
std::string getHostId(bool forAdmin)
void reportConsensusStateChange(ConsensusPhase phase)
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
void clearNeedNetworkLedger() override
SubInfoMapType subAccount_
HashMap< AccountID, HashMap< std::uint64_t, SubAccountHistoryInfoWeak > > SubAccountHistoryMapType
static constexpr std::size_t kAccountCleanupChunk
Maximum number of account entries erased per accountLock_ acquisition during disconnect-time cleanup.
bool subManifests(InfoSub::Ref ispListener) override
std::size_t const minPeerCount_
bool subServer(InfoSub::Ref ispListener, json::Value &jvResult, bool admin) override
std::vector< TransactionStatus > transactions_
bool subPeerStatus(InfoSub::Ref ispListener) override
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
void subMPT(InfoSub::Ref ispListener, HashSet< MPTID > const &mptIDs) override
void unsubAccount(InfoSub::Ref ispListener, HashSet< AccountID > const &vnaAccountIDs, bool rt) override
bool subValidations(InfoSub::Ref ispListener) override
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
std::condition_variable cond_
MultiApiJson transJson(std::shared_ptr< STTx const > const &transaction, TER result, bool validated, std::shared_ptr< ReadView const > const &ledger, std::optional< std::reference_wrapper< TxMeta const > > meta)
bool unsubManifests(std::uint64_t uListener) override
json::Value getOwnerInfo(std::shared_ptr< ReadView const > lpLedger, AccountID const &account) override
void unsubMPTInternal(std::uint64_t seq, MPTID const &mptID) override
Remove an MPT issuance subscription during InfoSub teardown.
HashMap< Book, SubMapType > SubBookMapType
Maps each order book to its current set of subscribers.
void cleanupAccountHistorySubscriptions(std::uint64_t seq, HashSet< AccountID > const &accounts)
Erase one connection's entries from subAccountHistory_ in accountLock_-bounded chunks.
void stateAccounting(json::Value &obj) override
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
DispatchState dispatchState_
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::Ref) override
void transactionBatch()
Apply transactions in batches.
void setTimer(boost::asio::steady_timer &timer, std::chrono::milliseconds const &expiryTime, std::function< void()> onExpire, std::function< void()> onError)
bool unsubRTTransactions(std::uint64_t uListener) override
beast::Journal const & journal() const override
Journal used by InfoSub for diagnostics that occur after the owning subsystem (e.g.
json::Value getLedgerFetchInfo() override
bool processTrustedProposal(RCLCxPeerPos proposal) override
InfoSub::pointer findRpcSubLocked(std::string const &strUrl)
Look up an RPC subscription without taking streamLock_.
void kickoffAccountHistory(std::shared_ptr< AcceptedLedger const > const &alpAccepted)
On the first published ledger only, start the delayed account-history streaming for any subscriptions...
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
void pubValidation(std::shared_ptr< STValidation > const &val) override
json::Value getConsensusInfo() override
ConsensusPhase lastConsensusPhase_
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
bool beginConsensus(UInt256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
void setMode(OperatingMode om) override
void setAmendmentBlocked() override
bool subBook(InfoSub::Ref ispListener, Book const &) override
ErrorCodeI subAccountHistory(InfoSub::Ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
HashMap< AccountID, SubMapType > SubInfoMapType
void pubConsensus(ConsensusPhase phase)
bool isNeedNetworkLedger() override
bool unsubBookInternal(std::uint64_t uListener, Book const &) override
Remove a book subscription during InfoSub teardown.
DispatchState
Synchronization states for transaction batches.
SubInfoMapType subRTAccount_
std::atomic< bool > needNetworkLedger_
boost::asio::steady_timer heartbeatTimer_
std::mutex mptLock_
Guards subMPT_.
std::array< SubMapType, SubTypes::SLastEntry > streamMaps_
One weak_ptr subscriber map per stream type.
std::reference_wrapper< ServiceRegistry > registry_
static std::array< char const *, 5 > const kStates
bool unsubLedger(std::uint64_t uListener) override
void pubProposedAccountTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result)
void unsubAccountHistoryInternal(std::uint64_t seq, AccountID const &account, bool historyOnly) override
void pubValidatedTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
void pubBookTransaction(AcceptedLedgerTx const &transaction, MultiApiJson const &jvObj)
Fan transaction notifications out to all book subscribers.
void cleanupAccountSubscriptions(std::uint64_t seq, HashSet< AccountID > const &accounts, SubInfoMapType &subMap)
Erase one connection's entries from the given account map (subAccount_ or subRTAccount_) in accountLo...
void switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
std::optional< PublicKey > const validatorPK_
std::mutex streamLock_
Guards streamMaps_[] and rpcSubMap_.
std::atomic< bool > amendmentBlocked_
bool unsubBook(InfoSub::Ref ispListener, Book const &) override
Remove a book subscription for a live subscriber.
void clearAmendmentWarned() override
LedgerMaster & ledgerMaster_
void publishLedgerStreams(std::shared_ptr< ReadView const > const &lpAccepted, std::shared_ptr< AcceptedLedger const > const &alpAccepted)
Send the ledgerClosed and book-changes stream updates for a ledger.
std::atomic< OperatingMode > mode_
void updateLocalTx(ReadView const &view) override
void clearLedgerFetch() override
std::unique_ptr< LocalTxs > localTX_
void apply(std::unique_lock< std::mutex > &batchLock)
Attempt to apply transactions and post-process based on the results.
InfoSub::pointer findRpcSub(std::string const &strUrl) override
bool isAmendmentBlocked() override
std::string strOperatingMode(OperatingMode const mode, bool const admin) const override
bool subBookChanges(InfoSub::Ref ispListener) override
HashMap< std::string, InfoSub::pointer > SubRpcMapType
void setStandAlone() override
void setNeedNetworkLedger() override
HashMap< MPTID, SubMapType > SubMPTInfoMapType
std::size_t getBookSubscribersCount() override
Total number of (book, subscriber) entries currently tracked.
std::mutex bookLock_
Guards subBook_.
bool unsubServer(std::uint64_t uListener) override
void processClusterTimer()
bool unsubConsensus(std::uint64_t uListener) override
bool subConsensus(InfoSub::Ref ispListener) override
void pubManifest(Manifest const &) override
std::mutex accountLock_
Guards subAccount_, subRTAccount_, subAccountHistory_.
void consensusViewChange() override
boost::asio::steady_timer accountHistoryTxTimer_
NetworkOPsImp(ServiceRegistry ®istry, NetworkOPs::ClockType &clock, bool standalone, std::size_t minPeerCount, bool startValid, JobQueue &jobQueue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &ioCtx, beast::Journal journal, beast::insight::Collector::Ptr const &collector)
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
void setUNLBlocked() override
bool unsubValidations(std::uint64_t uListener) override
void scheduleAccountCleanup(std::uint64_t seq, HashSet< AccountID > rtAccounts, HashSet< AccountID > normalAccounts, HashSet< AccountID > historyAccounts) override
Schedule the server-side teardown of a disconnecting connection's account subscriptions off the destr...
void pubMPTTransaction(AcceptedLedgerTx const &transaction, MultiApiJson const &jvObj)
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
std::set< UInt256 > pendingValidations_
bool subRTTransactions(InfoSub::Ref ispListener) override
OperatingMode getOperatingMode() const override
std::optional< PublicKey > const validatorMasterPK_
void doTransactionSyncBatch(std::unique_lock< std::mutex > &lock, std::function< bool(std::unique_lock< std::mutex > const &)> retryCallback)
HashMap< std::uint64_t, InfoSub::Wptr > SubMapType
bool tryRemoveRpcSub(std::string const &strUrl) override
void processHeartbeatTimer()
void doTransactionSync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failType)
For transactions submitted directly by a client, apply batch of transactions and wait for this transa...
void submitTransaction(std::shared_ptr< STTx const > const &) override
bool subTransactions(InfoSub::Ref ispListener) override
void setAmendmentWarned() override
void pubPeerStatus(std::function< json::Value(void)> const &) override
void unsubMPT(InfoSub::Ref ispListener, HashSet< MPTID > const &mptIDs) override
StateAccounting accounting_
SubAccountHistoryMapType subAccountHistory_
SubMPTInfoMapType subMPT_
Guarded by mptLock_.
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
std::atomic< bool > unlBlocked_
void unsubAccountHistory(InfoSub::Ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
bool subLedger(InfoSub::Ref ispListener, json::Value &jvResult) override
bool unsubBookChanges(std::uint64_t uListener) override
void unsubAccountInternal(std::uint64_t seq, HashSet< AccountID > const &vnaAccountIDs, bool rt) override
void setStateTimer() override
Called to initially start our timers.
std::size_t getLocalTxCount() override
bool preProcessTransaction(std::shared_ptr< Transaction > &transaction)
void processTransaction(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, FailHard failType) override
Process transactions as they arrive from the network or which are submitted by clients.
bool unsubTransactions(std::uint64_t uListener) override
bool isAmendmentWarned() override
void getBookPage(std::shared_ptr< ReadView const > &lpLedger, Book const &, AccountID const &uTakerID, bool const bProof, unsigned int iLimit, json::Value const &jvMarker, json::Value &jvResult) override
std::mutex validationsMutex_
std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay) override
Accepts the current transaction tree, return the new ledger's sequence.
void clearUNLBlocked() override
void subAccount(InfoSub::Ref ispListener, HashSet< AccountID > const &vnaAccountIDs, bool rt) override
bool isUNLBlocked() override
void pubProposedTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result) override
std::atomic< bool > amendmentWarned_
boost::asio::steady_timer clusterTimer_
void cleanupSubscriptionMap(std::uint64_t seq, HashSet< AccountID > const &accounts, OuterMap &outerMap, BeforeErase &&beforeErase)
Erase one connection's entries from a subscription map in accountLock_-bounded chunks.
bool checkLastClosedLedger(Overlay::PeerSequence const &, UInt256 &networkClosed)
bool unsubPeerStatus(std::uint64_t uListener) override
void reportFeeChange() override
ServerFeeSummary lastFeeSummary_
void processTransactionSet(CanonicalTXSet const &set) override
Process a set of transactions synchronously, and ensuring that they are processed in one batch.
void mapComplete(std::shared_ptr< SHAMap > const &map, bool fromAcquire) override
bool isBlocked() override
~NetworkOPsImp() override
json::Value getServerInfo(bool human, bool admin, bool counters) override
Provides server functionality for clients.
beast::AbstractClock< std::chrono::steady_clock > ClockType
Writable ledger view that accumulates state and tx changes.
std::vector< std::shared_ptr< Peer > > PeerSequence
Manages the generic consensus algorithm for use by the RCL.
A peer's signed, proposed position for use in RCLConsensus.
PublicKey const & publicKey() const
Public key of peer that sent the proposal.
Represents a set of transactions in RCLConsensus.
Wraps a ledger instance for use in generic Validations LedgerTrie.
static std::string getWordFromBlob(void const *blob, size_t bytes)
Chooses a single dictionary word from the data.
Collects logging information.
std::unique_ptr< std::stringstream > const & ss()
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
std::vector< AccountTx > AccountTxs
constexpr bool holds() const noexcept
std::string getText() const override
Asset const & asset() const
void setJson(json::Value &) const
std::shared_ptr< STLedgerEntry > pointer
std::shared_ptr< STLedgerEntry const > const_pointer
Automatically unlocks and re-locks a unique_lock object.
std::size_t size() const noexcept
void const * data() const noexcept
Service registry for dependency injection.
Validator keys and manifest as set in configuration file.
json::Value jsonClipped() const
constexpr double decimalXRP() const
T duration_cast(T... args)
T emplace_back(T... args)
void rngfill(void *const buffer, std::size_t const bytes, Generator &g)
JSON (JavaScript Object Notation).
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
std::string const & getVersionString()
Server version.
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
std::string const & getCommitHash()
std::string const & getBuildBranch()
Keylet offer(AccountID const &id, SeqProxy const &seq) noexcept
An offer from an account.
Keylet book(Book const &b)
The beginning of an order book.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet page(UInt256 const &root, std::uint64_t const index=0) noexcept
A page in a directory.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet child(UInt256 const &key) noexcept
Any item that can be in an owner dir.
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Encodes ledger sequence, transaction index, and network ID into a CTID string.
static constexpr std::integral_constant< unsigned, Version > kApiVersion
void insertAllSyntheticInJson(json::Value &metadata, ReadView const &ledger, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Adds all synthetic fields to transaction metadata JSON.
json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool cdirFirst(ReadView const &view, UInt256 const &root, SLE::const_pointer &page, unsigned int &index, UInt256 &entry)
Returns the first entry in the directory, advancing the index.
@ WarnRpcAmendmentBlocked
@ WarnRpcUnsupportedMajority
@ WarnRpcExpiredValidatorList
STAmount divide(STAmount const &amount, Rate const &rate)
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
constexpr FlagValue tfInnerBatchTxn
bool isTerRetry(TER x) noexcept
void handleNewValidation(Application &app, std::shared_ptr< STValidation > const &val, std::string const &source, BypassAccept const bypassAccept, std::optional< beast::Journal > j)
Handle a new validation.
UInt256 getBookBase(Book const &book)
@ WrongLedger
We have the wrong ledger and are attempting to acquire it.
@ Proposing
We are normal participant in consensus and propose our position.
std::optional< std::uint64_t > mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
Return value*mul/div accurately.
SendIfPred< Predicate > sendIf(std::shared_ptr< Message > const &m, Predicate const &f)
Helper function to aid in type deduction.
void forAllApiVersions(Fn const &fn, Args &&... args)
@ SigBad
Signature is bad.
@ Valid
Signature and local checks are good / passed.
T get(Section const §ion, std::string const &name, T const &defaultValue=T{})
Retrieve a key/value pair from a section.
constexpr std::size_t kMaxPoppedTransactions
std::string strHex(FwdIt begin, FwdIt end)
std::uint64_t getQuality(UInt256 const &uBase)
std::unique_ptr< FeeVote > makeFeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules)
Checks transaction signature and local checks.
Rules makeRulesGivenLedger(DigestAwareReadView const &ledger, Rules const ¤t)
FeeSetup setupFeeVote(Section const §ion)
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::unique_ptr< NetworkOPs > makeNetworkOPs(ServiceRegistry ®istry, NetworkOPs::ClockType &clock, bool standalone, std::size_t minPeerCount, bool startValid, JobQueue &jobQueue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &ioSvc, beast::Journal journal, beast::insight::Collector::Ptr const &collector)
UInt256 getQualityNext(UInt256 const &uBase)
Number root(Number f, unsigned d)
CsprngEngine & cryptoPrng()
The default cryptographically secure PRNG.
bool transResultInfo(TER code, std::string &token, std::string &text)
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
constexpr Dest safeCast(Src s) noexcept
std::string transToken(TER code)
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
constexpr std::uint32_t kFeeUnitsDeprecated
std::string to_string(BaseUInt< Bits, Tag > const &a)
std::string toStringIso(date::sys_time< Duration > tp)
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Check if the issuer has the global freeze flag set.
STAmount amountFromQuality(std::uint64_t rate)
bool isTefFailure(TER x) noexcept
HashSet< Book > affectedBooks(AcceptedLedgerTx const &alTx, beast::Journal const &j)
Extract the set of books affected by a transaction.
std::unique_ptr< LocalTxs > makeLocalTxs()
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
ConsensusPhase
Phases of consensus for a single ledger round.
@ Open
We haven't closed our ledger yet, but others might have.
Rate const kParityRate
A transfer rate signifying a 1:1 exchange.
json::Value getJson(LedgerFill const &fill)
Return a new json::Value representing the ledger with given options.
std::unordered_set< Value, Hash, Pred, Allocator > HashSet
bool cdirNext(ReadView const &view, UInt256 const &root, SLE::const_pointer &page, unsigned int &index, UInt256 &entry)
Returns the next entry in the directory, advancing the index.
AccountID calcAccountID(PublicKey const &pk)
static std::array< char const *, 5 > const kStateNames
constexpr auto kMuldivMax
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
detail::MultiApiJson< rpc::kApiMinimumSupportedVersion, rpc::kApiMaximumValidVersion > MultiApiJson
bool isTelLocal(TER x) noexcept
bool isTesSuccess(TER x) noexcept
static std::uint32_t trunc32(std::uint64_t v)
TERSubset< CanCvtToTER > TER
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
std::unordered_map< Key, Value, Hash, Pred, Allocator > HashMap
OperatingMode
Specifies the mode under which the server believes it's operating.
@ TRACKING
convinced we agree with the network
@ DISCONNECTED
not ready to process requests
@ CONNECTED
convinced we are talking to the network
@ FULL
we have the ledger and can even validate
@ SYNCING
fallen slightly behind
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
STAmount issuerFundsToSelfIssue(ReadView const &view, MPTIssue const &issue)
Determine funds available for an issuer to sell in an issuer owned offer.
static auto const kGenesisAccountId
bool isTemMalformed(TER x) noexcept
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
STAmount toSTAmount(IOUAmount const &iou, Asset const &asset)
CanonicalTXSet OrderedTxs
T set_intersection(T... args)
static constexpr auto kPort
static constexpr auto kIp
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
Blob getMasterSignature() const
Returns manifest master key signature.
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
std::optional< Blob > getSignature() const
Returns manifest signature.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
Server fees published on server subscription.
std::optional< TxQ::Metrics > em
bool operator!=(ServerFeeSummary const &b) const
bool operator==(ServerFeeSummary const &b) const
std::uint32_t loadBaseServer
ServerFeeSummary()=default
std::uint32_t loadFactorServer
decltype(initialSyncUs_) initialSyncUs
decltype(counters_) counters
std::chrono::microseconds dur
std::uint64_t transitions
beast::insight::Gauge fullTransitions
beast::insight::Gauge disconnectedTransitions
beast::insight::Gauge connectedDuration
beast::insight::Gauge trackingTransitions
beast::insight::Gauge fullDuration
beast::insight::Gauge syncingDuration
Stats(Handler const &handler, beast::insight::Collector::Ptr const &collector)
beast::insight::Gauge disconnectedDuration
beast::insight::Gauge connectedTransitions
beast::insight::Gauge trackingDuration
beast::insight::Hook hook
beast::insight::Gauge syncingTransitions
std::uint32_t historyLastLedgerSeq
std::atomic< bool > stopHistorical
SubAccountHistoryIndex(AccountID const &accountId)
AccountID const accountId
std::int32_t historyTxIndex
std::uint32_t separationLedgerSeq
std::uint32_t forwardTxIndex
std::shared_ptr< SubAccountHistoryIndex > index
std::shared_ptr< SubAccountHistoryIndex > index
Select all peers (except optional excluded) that are in our cluster.
Represents a transfer rate.
static constexpr auto kPortGrpc
Sends a message to all peers.
Changes in trusted nodes after updating validator list.
HashSet< NodeID > removed
Structure returned by TxQ::getMetrics, expressed in reference fee level units.
void set(char const *key, auto const &v)
IsMemberResult isMember(char const *key) const
Data format for exchanging consumption information across peers.
std::vector< Item > items
T time_since_epoch(T... args)