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/consensus/ConsensusParms.h>
25#include <xrpld/consensus/ConsensusTypes.h>
26#include <xrpld/core/Config.h>
27#include <xrpld/overlay/Cluster.h>
28#include <xrpld/overlay/ClusterNode.h>
29#include <xrpld/overlay/Overlay.h>
30#include <xrpld/overlay/predicates.h>
31#include <xrpld/rpc/BookChanges.h>
32#include <xrpld/rpc/CTID.h>
33#include <xrpld/rpc/DeliveredAmount.h>
34#include <xrpld/rpc/MPTokenIssuanceID.h>
35#include <xrpld/rpc/ServerHandler.h>
37#include <xrpl/basics/Log.h>
38#include <xrpl/basics/ToString.h>
39#include <xrpl/basics/UnorderedContainers.h>
40#include <xrpl/basics/UptimeClock.h>
41#include <xrpl/basics/base_uint.h>
42#include <xrpl/basics/chrono.h>
43#include <xrpl/basics/contract.h>
44#include <xrpl/basics/mulDiv.h>
45#include <xrpl/basics/safe_cast.h>
46#include <xrpl/basics/scope.h>
47#include <xrpl/basics/strHex.h>
48#include <xrpl/beast/clock/abstract_clock.h>
49#include <xrpl/beast/insight/Collector.h>
50#include <xrpl/beast/insight/Gauge.h>
51#include <xrpl/beast/insight/Hook.h>
52#include <xrpl/beast/net/IPEndpoint.h>
53#include <xrpl/beast/utility/Zero.h>
54#include <xrpl/beast/utility/instrumentation.h>
55#include <xrpl/beast/utility/rngfill.h>
56#include <xrpl/config/Constants.h>
57#include <xrpl/core/ClosureCounter.h>
58#include <xrpl/core/HashRouter.h>
59#include <xrpl/core/Job.h>
60#include <xrpl/core/NetworkIDService.h>
61#include <xrpl/core/PerfLog.h>
62#include <xrpl/core/ServiceRegistry.h>
63#include <xrpl/crypto/RFC1751.h>
64#include <xrpl/crypto/csprng.h>
65#include <xrpl/git/Git.h>
66#include <xrpl/json/json_forwards.h>
67#include <xrpl/json/json_value.h>
68#include <xrpl/json/json_writer.h>
69#include <xrpl/ledger/AcceptedLedgerTx.h>
70#include <xrpl/ledger/AmendmentTable.h>
71#include <xrpl/ledger/ApplyView.h>
72#include <xrpl/ledger/CanonicalTXSet.h>
73#include <xrpl/ledger/Ledger.h>
74#include <xrpl/ledger/OpenView.h>
75#include <xrpl/ledger/OrderBookDB.h>
76#include <xrpl/ledger/ReadView.h>
77#include <xrpl/ledger/helpers/AccountRootHelpers.h>
78#include <xrpl/ledger/helpers/DirectoryHelpers.h>
79#include <xrpl/ledger/helpers/TokenHelpers.h>
80#include <xrpl/protocol/AccountID.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/KeyType.h>
89#include <xrpl/protocol/LedgerFormats.h>
90#include <xrpl/protocol/MultiApiJson.h>
91#include <xrpl/protocol/NFTSyntheticSerializer.h>
92#include <xrpl/protocol/Protocol.h>
93#include <xrpl/protocol/PublicKey.h>
94#include <xrpl/protocol/RPCErr.h>
95#include <xrpl/protocol/Rate.h>
96#include <xrpl/protocol/SField.h>
97#include <xrpl/protocol/STAmount.h>
98#include <xrpl/protocol/STTx.h>
99#include <xrpl/protocol/SecretKey.h>
100#include <xrpl/protocol/Seed.h>
101#include <xrpl/protocol/Serializer.h>
102#include <xrpl/protocol/TER.h>
103#include <xrpl/protocol/TxFlags.h>
104#include <xrpl/protocol/TxFormats.h>
105#include <xrpl/protocol/Units.h>
106#include <xrpl/protocol/XRPAmount.h>
107#include <xrpl/protocol/jss.h>
108#include <xrpl/protocol/tokens.h>
109#include <xrpl/rdb/RelationalDatabase.h>
110#include <xrpl/resource/Fees.h>
111#include <xrpl/resource/Gossip.h>
112#include <xrpl/resource/ResourceManager.h>
113#include <xrpl/server/InfoSub.h>
114#include <xrpl/server/LoadFeeTrack.h>
115#include <xrpl/server/Manifest.h>
116#include <xrpl/shamap/SHAMap.h>
117#include <xrpl/tx/apply.h>
119#include <boost/asio/error.hpp>
120#include <boost/asio/io_context.hpp>
121#include <boost/asio/ip/host_name.hpp>
122#include <boost/asio/steady_timer.hpp>
123#include <boost/system/detail/errc.hpp>
124#include <boost/system/detail/error_code.hpp>
125#include <boost/system/system_error.hpp>
178 "xrpl::NetworkOPsImp::TransactionStatus::TransactionStatus : "
284 return !(*
this != b);
303 boost::asio::io_context& ioCtx,
320 registry.getInboundTransactions(),
321 beast::getAbstractClock<
std::chrono::steady_clock>(),
325 validatorKeys.keys ? validatorKeys.keys->publicKey : decltype(
validatorPK_){})
327 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
514 getServerInfo(
bool human,
bool admin,
bool counters)
override;
542 TER result)
override;
650 catch (boost::system::system_error
const& e)
652 JLOG(
journal_.error()) <<
"NetworkOPs: heartbeatTimer cancel error: " << e.what();
659 catch (boost::system::system_error
const& e)
661 JLOG(
journal_.error()) <<
"NetworkOPs: clusterTimer cancel error: " << e.what();
668 catch (boost::system::system_error
const& e)
671 <<
"NetworkOPs: accountHistoryTxTimer cancel error: " << e.what();
675 using namespace std::chrono_literals;
685 boost::asio::steady_timer& timer,
900 template <
class Handler>
902 :
hook(collector->makeHook(handler))
904 collector->makeGauge(
"State_Accounting",
"Disconnected_duration"))
905 ,
connectedDuration(collector->makeGauge(
"State_Accounting",
"Connected_duration"))
906 ,
syncingDuration(collector->makeGauge(
"State_Accounting",
"Syncing_duration"))
907 ,
trackingDuration(collector->makeGauge(
"State_Accounting",
"Tracking_duration"))
908 ,
fullDuration(collector->makeGauge(
"State_Accounting",
"Full_duration"))
910 collector->makeGauge(
"State_Accounting",
"Disconnected_transitions"))
912 collector->makeGauge(
"State_Accounting",
"Connected_transitions"))
915 ,
fullTransitions(collector->makeGauge(
"State_Accounting",
"Full_transitions"))
944 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
1004 static std::string const kHostname = boost::asio::ip::host_name();
1011 static std::string const kShroudedHostId = [
this]() {
1012 auto const&
id =
registry_.get().getApp().nodeIdentity();
1017 return kShroudedHostId;
1026 if (
registry_.get().getCluster().size() != 0)
1032 boost::asio::steady_timer& timer,
1038 if (
auto optionalCountedHandler =
1040 if ((e.value() == boost::system::errc::success) && (!jobQueue_.isStopped()))
1045 if (e.value() != boost::system::errc::success &&
1046 e.value() != boost::asio::error::operation_aborted)
1049 JLOG(journal_.error())
1050 <<
"Timer got error '" << e.message() <<
"'. Restarting timer.";
1055 timer.expires_after(expiryTime);
1056 timer.async_wait(std::move(*optionalCountedHandler));
1067 jobQueue_.addJob(JtNetopTimer,
"NetHeart", [this]() { processHeartbeatTimer(); });
1069 [
this]() { setHeartbeatTimer(); });
1075 using namespace std::chrono_literals;
1089 JLOG(
journal_.debug()) <<
"Scheduling AccountHistory job for account "
1091 using namespace std::chrono_literals;
1119 ss <<
"Node count (" << numPeers <<
") has fallen "
1122 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
1126 CLOG(clog.
ss()) <<
"already DISCONNECTED. too few peers (" << numPeers
1142 JLOG(
journal_.info()) <<
"Node count (" << numPeers <<
") is sufficient.";
1143 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers <<
" peers. ";
1148 auto origMode =
mode_.load();
1158 auto newMode =
mode_.load();
1159 if (origMode != newMode)
1163 CLOG(clog.
ss()) <<
". ";
1176 CLOG(clog.
ss()) <<
". ";
1184 if (
registry_.get().getCluster().size() == 0)
1187 using namespace std::chrono_literals;
1189 bool const update =
registry_.get().getCluster().update(
1190 registry_.get().getApp().nodeIdentity().first,
1193 ?
registry_.get().getFeeTrack().getLocalFee()
1199 JLOG(
journal_.debug()) <<
"Too soon to send cluster update";
1204 protocol::TMCluster cluster;
1206 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1211 n.set_nodename(node.
name());
1215 for (
auto& item : gossip.
items)
1217 protocol::TMLoadSource& node = *cluster.add_loadsources();
1219 node.set_cost(item.balance);
1233 auto const consensusMode =
consensus_.mode();
1240 return "validating";
1259 JLOG(
journal_.error()) <<
"Submitted transaction invalid: tfInnerBatchTxn flag present.";
1266 auto const txid = trans->getTransactionID();
1267 auto const flags =
registry_.get().getHashRouter().getFlags(txid);
1271 JLOG(
journal_.warn()) <<
"Submitted transaction cached bad";
1282 JLOG(
journal_.warn()) <<
"Submitted transaction invalid: " << reason;
1288 JLOG(
journal_.warn()) <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1306 auto const newFlags =
registry_.get().getHashRouter().getFlags(transaction->getID());
1311 JLOG(
journal_.warn()) << transaction->getID() <<
": cached bad!\n";
1322 auto const sttx = *transaction->getSTransaction();
1323 if (sttx.isFlag(
tfInnerBatchTxn) && view->rules().enabled(featureBatch))
1334 auto const [validity, reason] =
1337 validity ==
Validity::Valid,
"xrpl::NetworkOPsImp::processTransaction : valid validity");
1342 JLOG(
journal_.info()) <<
"Transaction has bad signature: " << reason;
1350 registry_.get().getMasterTransaction().canonicalize(&transaction);
1386 if (transaction->getApplying())
1389 transactions_.emplace_back(transaction, bUnlimited,
false, failType);
1390 transaction->setApplying();
1394 if (
jobQueue_.addJob(
JtBatch,
"TxBatchAsync", [
this]() { transactionBatch(); }))
1409 if (!transaction->getApplying())
1411 transactions_.emplace_back(transaction, bUnlimited,
true, failType);
1412 transaction->setApplying();
1416 return transaction->getApplying();
1439 if (
jobQueue_.addJob(
JtBatch,
"TxBatchSync", [
this]() { transactionBatch(); }))
1445 }
while (retryCallback(lock));
1454 for (
auto const& [_, tx] :
set)
1461 if (!reason.
empty())
1463 JLOG(
journal_.trace()) <<
"Exception checking transaction: " << reason;
1481 for (
auto& transaction : candidates)
1483 if (!transaction->getApplying())
1486 transaction->setApplying();
1502 JLOG(
journal_.debug()) <<
"No transaction to process!";
1507 XRPL_ASSERT(lock.owns_lock(),
"xrpl::NetworkOPsImp::processTransactionSet has lock");
1509 transactions_, [](
auto const& t) {
return t.transaction->getApplying(); });
1533 XRPL_ASSERT(!
transactions.empty(),
"xrpl::NetworkOPsImp::apply : non-empty transactions");
1543 bool changed =
false;
1558 auto const result =
registry_.get().getTxQ().apply(
1559 registry_.get().getApp(), view, e.transaction->getSTransaction(), flags, j);
1560 e.result = result.ter;
1561 e.applied = result.applied;
1562 changed = changed || result.applied;
1572 validatedLedgerIndex = l->header().seq;
1574 auto newOL =
registry_.get().getOpenLedger().current();
1577 e.transaction->clearSubmitResult();
1582 e.transaction->setApplied();
1585 e.transaction->setResult(e.result);
1589 registry_.get().getHashRouter().setFlags(
1600 JLOG(
journal_.info()) <<
"TransactionResult: " << token <<
": " << human;
1605 bool const addLocal = e.local;
1609 JLOG(
journal_.debug()) <<
"Transaction is now included in open ledger";
1615 auto const& txCur = e.transaction->getSTransaction();
1627 if (t->getApplying())
1638 JLOG(
journal_.info()) <<
"Transaction is obsolete";
1643 JLOG(
journal_.debug()) <<
"Transaction is likely to claim a"
1644 <<
" fee, but is queued until fee drops";
1651 e.transaction->setQueued();
1652 e.transaction->setKept();
1658 auto const lastLedgerSeq =
1659 e.transaction->getSTransaction()->at(~sfLastLedgerSequence);
1660 auto const ledgersLeft = lastLedgerSeq
1680 registry_.get().getHashRouter().setFlags(
1684 JLOG(
journal_.debug()) <<
"Transaction should be held: " << e.result;
1687 e.transaction->setKept();
1692 <<
"Not holding transaction " << e.transaction->getID() <<
": "
1693 << (e.local ?
"local" :
"network") <<
", "
1694 <<
"result: " << e.result <<
" ledgers left: "
1695 << (ledgersLeft ?
to_string(*ledgersLeft) :
"unspecified");
1701 JLOG(
journal_.debug()) <<
"Status other than success " << e.result;
1707 if (addLocal && !enforceFailHard)
1710 ledgerMaster_.getCurrentLedgerIndex(), e.transaction->getSTransaction());
1711 e.transaction->setKept();
1720 registry_.get().getHashRouter().shouldRelay(e.transaction->getID());
1721 if (
auto const sttx = *(e.transaction->getSTransaction()); toSkip &&
1728 protocol::TMTransaction tx;
1732 tx.set_rawtransaction(s.
data(), s.
size());
1733 tx.set_status(protocol::tsCURRENT);
1734 tx.set_receivetimestamp(
1735 registry_.get().getTimeKeeper().now().time_since_epoch().count());
1738 registry_.get().getOverlay().relay(e.transaction->getID(), tx, *toSkip);
1739 e.transaction->setBroadcast();
1743 if (validatedLedgerIndex)
1745 auto [fee, accountSeq, availableSeq] =
1746 registry_.get().getTxQ().getTxRequiredFeeAndSeq(
1747 *newOL, e.transaction->getSTransaction());
1748 e.transaction->setCurrentLedgerState(
1749 *validatedLedgerIndex, fee, accountSeq, availableSeq);
1757 e.transaction->clearApplying();
1759 if (!submitHeld.
empty())
1768 for (
auto& e : submitHeld)
1794 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1797 XRPL_ASSERT(sleCur,
"xrpl::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1799 switch (sleCur->getType())
1802 if (!jvObjects.
isMember(jss::offers))
1808 case ltRIPPLE_STATE:
1809 if (!jvObjects.
isMember(jss::ripple_lines))
1814 jvObjects[jss::ripple_lines].
append(
1818 case ltACCOUNT_ROOT:
1823 "xrpl::NetworkOPsImp::getOwnerInfo : invalid "
1830 uNodeDir = sleNode->getFieldU64(sfIndexNext);
1835 XRPL_ASSERT(sleNode,
"xrpl::NetworkOPsImp::getOwnerInfo : read next page");
1837 }
while (uNodeDir != 0u);
1911 JLOG(
journal_.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
1918 uint256 closedLedger = ourClosed->header().hash;
1919 uint256 const prevClosedLedger = ourClosed->header().parentHash;
1920 JLOG(
journal_.trace()) <<
"OurClosed: " << closedLedger;
1921 JLOG(
journal_.trace()) <<
"PrevClosed: " << prevClosedLedger;
1926 auto& validations =
registry_.get().getValidations();
1931 peerCounts[closedLedger] = 0;
1933 peerCounts[closedLedger]++;
1935 for (
auto& peer : peerList)
1937 uint256 const peerLedger = peer->getClosedLedgerHash();
1940 ++peerCounts[peerLedger];
1943 for (
auto const& it : peerCounts)
1944 JLOG(
journal_.debug()) <<
"L: " << it.first <<
" n=" << it.second;
1946 uint256 const preferredLCL = validations.getPreferredLCL(
1951 bool switchLedgers = preferredLCL != closedLedger;
1953 closedLedger = preferredLCL;
1955 if (switchLedgers && (closedLedger == prevClosedLedger))
1958 JLOG(
journal_.info()) <<
"We won't switch to our own previous ledger";
1959 networkClosed = ourClosed->header().hash;
1960 switchLedgers =
false;
1964 networkClosed = closedLedger;
1970 auto consensus =
ledgerMaster_.getLedgerByHash(closedLedger);
1974 consensus =
registry_.get().getInboundLedgers().acquire(
1984 networkClosed = ourClosed->header().hash;
1988 JLOG(
journal_.warn()) <<
"We are not running on the consensus ledger";
1989 JLOG(
journal_.info()) <<
"Our LCL: " << ourClosed->header().hash <<
getJson({*ourClosed, {}});
1990 JLOG(
journal_.info()) <<
"Net LCL " << closedLedger;
2012 JLOG(
journal_.error()) <<
"JUMP last closed ledger to " << newLCL->header().hash;
2017 registry_.get().getTxQ().processClosedLedger(
registry_.get().getApp(), *newLCL,
true);
2024 auto retries =
localTX_->getTxSet();
2025 auto const lastVal =
registry_.get().getLedgerMaster().getValidatedLedger();
2052 protocol::TMStatusChange s;
2053 s.set_newevent(protocol::neSWITCHED_LEDGER);
2054 s.set_ledgerseq(newLCL->header().seq);
2055 s.set_networktime(
registry_.get().getTimeKeeper().now().time_since_epoch().count());
2056 s.set_ledgerhashprevious(
2057 newLCL->header().parentHash.begin(), newLCL->header().parentHash.size());
2058 s.set_ledgerhash(newLCL->header().hash.begin(), newLCL->header().hash.size());
2068 XRPL_ASSERT(networkClosed.
isNonZero(),
"xrpl::NetworkOPsImp::beginConsensus : nonzero input");
2070 auto closingInfo =
ledgerMaster_.getCurrentLedger()->header();
2072 JLOG(
journal_.info()) <<
"Consensus time for #" << closingInfo.seq <<
" with LCL "
2073 << closingInfo.parentHash;
2075 auto prevLedger =
ledgerMaster_.getLedgerByHash(closingInfo.parentHash);
2082 JLOG(
journal_.warn()) <<
"Don't have LCL, going to tracking";
2084 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
2087 CLOG(clog) <<
"beginConsensus no previous ledger. ";
2092 prevLedger->header().hash == closingInfo.parentHash,
2093 "xrpl::NetworkOPsImp::beginConsensus : prevLedger hash matches "
2096 closingInfo.parentHash ==
ledgerMaster_.getClosedLedger()->header().hash,
2097 "xrpl::NetworkOPsImp::beginConsensus : closedLedger parent matches "
2100 registry_.get().getValidators().setNegativeUNL(prevLedger->negativeUNL());
2102 registry_.get().getValidations().getCurrentNodeIDs(),
2103 closingInfo.parentCloseTime,
2108 if (!changes.
added.empty() || !changes.
removed.empty())
2112 registry_.get().getAmendmentTable().trustChanged(
2113 registry_.get().getValidators().getQuorumKeys().second);
2117 registry_.get().getTimeKeeper().closeTime(),
2131 JLOG(
journal_.debug()) <<
"Initiating consensus engine";
2138 auto const& peerKey = peerPos.
publicKey();
2150 JLOG(
journal_.error()) <<
"Received a proposal signed by MY KEY from a peer. This may "
2151 "indicate a misconfiguration where another node has the same "
2152 "validator key, or may be caused by unusual message routing and "
2165 protocol::TMHaveTransactionSet msg;
2166 msg.set_hash(map->getHash().asUInt256().begin(), 256 / 8);
2167 msg.set_status(protocol::tsHAVE);
2180 for (
auto const& it :
registry_.get().getOverlay().getActivePeers())
2182 if (it && (it->getClosedLedgerHash() == deadLedger))
2184 JLOG(
journal_.trace()) <<
"Killing obsolete peer status";
2190 bool const ledgerChange =
2193 if (networkClosed.
isZero())
2195 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
2221 if (
registry_.get().getTimeKeeper().now() <
2222 (current->header().parentCloseTime + 2 * current->header().closeTimeResolution))
2250 jvObj[jss::type] =
"manifestReceived";
2256 jvObj[jss::signature] =
strHex(*sig);
2259 jvObj[jss::domain] = mo.
domain;
2264 if (
auto p = i->second.lock())
2266 p->send(jvObj,
true);
2284 ,
em{escalationMetrics}
2298 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2299 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2300 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2329 registry_.get().getOpenLedger().current()->fees().base,
2333 jvObj[jss::type] =
"serverStatus";
2346 jvObj[jss::load_factor] =
trunc32(loadFactor);
2347 jvObj[jss::load_factor_fee_escalation] = f.
em->openLedgerFeeLevel.jsonClipped();
2348 jvObj[jss::load_factor_fee_queue] = f.
em->minProcessingFeeLevel.jsonClipped();
2349 jvObj[jss::load_factor_fee_reference] = f.
em->referenceFeeLevel.jsonClipped();
2367 p->send(jvObj,
true);
2384 if (!streamMap.empty())
2387 jvObj[jss::type] =
"consensusPhase";
2388 jvObj[jss::consensus] =
to_string(phase);
2390 for (
auto i = streamMap.begin(); i != streamMap.end();)
2392 if (
auto p = i->second.lock())
2394 p->send(jvObj,
true);
2399 i = streamMap.erase(i);
2415 auto const signerPublic = val->getSignerPublic();
2417 jvObj[jss::type] =
"validationReceived";
2419 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2420 jvObj[jss::signature] =
strHex(val->getSignature());
2421 jvObj[jss::full] = val->isFull();
2422 jvObj[jss::flags] = val->getFlags();
2423 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2424 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2425 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
2427 if (
auto version = (*val)[~sfServerVersion])
2430 if (
auto cookie = (*val)[~sfCookie])
2433 if (
auto hash = (*val)[~sfValidatedHash])
2434 jvObj[jss::validated_hash] =
strHex(*hash);
2436 auto const masterKey =
registry_.get().getValidatorManifests().getMasterKey(signerPublic);
2438 if (masterKey != signerPublic)
2443 if (
auto const seq = (*val)[~sfLedgerSequence])
2444 jvObj[jss::ledger_index] = *seq;
2446 if (val->isFieldPresent(sfAmendments))
2449 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2453 if (
auto const closeTime = (*val)[~sfCloseTime])
2454 jvObj[jss::close_time] = *closeTime;
2456 if (
auto const loadFee = (*val)[~sfLoadFee])
2457 jvObj[jss::load_fee] = *loadFee;
2459 if (
auto const baseFee = val->at(~sfBaseFee))
2460 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2462 if (
auto const reserveBase = val->at(~sfReserveBase))
2463 jvObj[jss::reserve_base] = *reserveBase;
2465 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2466 jvObj[jss::reserve_inc] = *reserveInc;
2470 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); baseFeeXRP && baseFeeXRP->native())
2471 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2473 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
2474 reserveBaseXRP && reserveBaseXRP->native())
2475 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2477 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
2478 reserveIncXRP && reserveIncXRP->native())
2479 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2488 if (jvTx.
isMember(jss::ledger_index))
2490 jvTx[jss::ledger_index] =
std::to_string(jvTx[jss::ledger_index].asUInt());
2496 if (
auto p = i->second.lock())
2500 [&](
json::Value const& jv) { p->send(jv, true); });
2520 jvObj[jss::type] =
"peerStatusChange";
2528 p->send(jvObj,
true);
2542 using namespace std::chrono_literals;
2545 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() < 1min)
2550 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() >= 1min)
2571 JLOG(
journal_.trace()) <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2590 JLOG(
journal_.warn()) <<
"Exception thrown for handling new validation "
2591 << val->getLedgerHash() <<
": " << e.
what();
2595 JLOG(
journal_.warn()) <<
"Unknown exception thrown for handling new validation "
2596 << val->getLedgerHash();
2606 JLOG(
journal_.debug()) << [
this, &val]() ->
auto {
2608 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2609 auto master =
registry_.get().getValidators().getTrustedKey(val->getSignerPublic());
2623 return registry_.get().getApp().config().relayUntrustedValidations == 1 || val->isTrusted();
2645 "This server is amendment blocked, and must be updated to be "
2646 "able to stay in sync with the network.";
2653 "This server has an expired validator list. validators.txt "
2654 "may be incorrectly configured or some [validator_list_sites] "
2655 "may be unreachable.";
2662 "One or more unsupported amendments have reached majority. "
2663 "Upgrade to the latest version before they are activated "
2664 "to avoid being amendment blocked.";
2665 if (
auto const expected =
2666 registry_.get().getAmendmentTable().firstUnsupportedExpected())
2669 d[jss::expected_date] = expected->time_since_epoch().count();
2670 d[jss::expected_date_UTC] =
to_string(*expected);
2674 if (warnings.
size() != 0u)
2675 info[jss::warnings] = std::move(warnings);
2683 if (!
registry_.get().getApp().config().serverDomain.empty())
2684 info[jss::server_domain] =
registry_.get().getApp().config().serverDomain;
2694 info[jss::network_ledger] =
"waiting";
2696 info[jss::validation_quorum] =
2704 switch (
registry_.get().getApp().config().nodeSize)
2707 info[jss::node_size] =
"tiny";
2710 info[jss::node_size] =
"small";
2713 info[jss::node_size] =
"medium";
2716 info[jss::node_size] =
"large";
2719 info[jss::node_size] =
"huge";
2723 auto when =
registry_.get().getValidators().expires();
2729 info[jss::validator_list_expires] =
2734 info[jss::validator_list_expires] = 0;
2745 if (*when == TimeKeeper::time_point::max())
2747 x[jss::expiration] =
"never";
2748 x[jss::status] =
"active";
2754 if (*when >
registry_.get().getTimeKeeper().now())
2756 x[jss::status] =
"active";
2760 x[jss::status] =
"expired";
2766 x[jss::status] =
"unknown";
2767 x[jss::expiration] =
"unknown";
2780 info[jss::io_latency_ms] =
2785 if (
auto const localPubKey =
registry_.get().getValidators().localPublicKey();
2786 localPubKey &&
registry_.get().getApp().getValidationPublicKey())
2792 info[jss::pubkey_validator] =
"none";
2798 info[jss::counters] =
registry_.get().getPerfLog().countersJson();
2801 registry_.get().getNodeStore().getCountsJson(nodestore);
2802 info[jss::counters][jss::nodestore] = nodestore;
2803 info[jss::current_activities] =
registry_.get().getPerfLog().currentJson();
2806 info[jss::pubkey_node] =
2809 info[jss::complete_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
2812 info[jss::amendment_blocked] =
true;
2826 lastClose[jss::converge_time_s] =
2834 info[jss::last_close] = lastClose;
2841 if (
auto const netid =
registry_.get().getOverlay().networkID())
2842 info[jss::network_id] =
static_cast<json::UInt>(*netid);
2844 auto const escalationMetrics =
2847 auto const loadFactorServer =
registry_.get().getFeeTrack().getLoadFactor();
2848 auto const loadBaseServer =
registry_.get().getFeeTrack().getLoadBase();
2852 auto const loadFactorFeeEscalation =
mulDiv(
2853 escalationMetrics.openLedgerFeeLevel,
2855 escalationMetrics.referenceFeeLevel)
2858 auto const loadFactor =
2863 info[jss::load_base] = loadBaseServer;
2864 info[jss::load_factor] =
trunc32(loadFactor);
2865 info[jss::load_factor_server] = loadFactorServer;
2872 info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.jsonClipped();
2873 info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.jsonClipped();
2874 info[jss::load_factor_fee_reference] = escalationMetrics.referenceFeeLevel.jsonClipped();
2878 info[jss::load_factor] =
static_cast<double>(loadFactor) / loadBaseServer;
2880 if (loadFactorServer != loadFactor)
2881 info[jss::load_factor_server] =
static_cast<double>(loadFactorServer) / loadBaseServer;
2886 if (fee != loadBaseServer)
2887 info[jss::load_factor_local] =
static_cast<double>(fee) / loadBaseServer;
2888 fee =
registry_.get().getFeeTrack().getRemoteFee();
2889 if (fee != loadBaseServer)
2890 info[jss::load_factor_net] =
static_cast<double>(fee) / loadBaseServer;
2891 fee =
registry_.get().getFeeTrack().getClusterFee();
2892 if (fee != loadBaseServer)
2893 info[jss::load_factor_cluster] =
static_cast<double>(fee) / loadBaseServer;
2895 if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel &&
2896 (admin || loadFactorFeeEscalation != loadFactor))
2898 info[jss::load_factor_fee_escalation] =
2899 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
2900 escalationMetrics.referenceFeeLevel);
2902 if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel)
2904 info[jss::load_factor_fee_queue] =
2905 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
2906 escalationMetrics.referenceFeeLevel);
2924 XRPAmount const baseFee = lpClosed->fees().base;
2926 l[jss::seq] =
json::UInt(lpClosed->header().seq);
2927 l[jss::hash] =
to_string(lpClosed->header().hash);
2932 l[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
2933 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
2934 l[jss::close_time] =
2940 l[jss::reserve_base_xrp] = lpClosed->fees().reserve.decimalXRP();
2941 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
2943 if (
auto const closeOffset =
registry_.get().getTimeKeeper().closeOffset();
2944 std::abs(closeOffset.count()) >= 60)
2945 l[jss::close_time_offset] =
static_cast<std::uint32_t>(closeOffset.count());
2955 auto lCloseTime = lpClosed->header().closeTime;
2956 auto closeTime =
registry_.get().getTimeKeeper().closeTime();
2957 if (lCloseTime <= closeTime)
2959 using namespace std::chrono_literals;
2960 auto age = closeTime - lCloseTime;
2968 info[jss::validated_ledger] = l;
2972 info[jss::closed_ledger] = l;
2978 info[jss::published_ledger] =
"none";
2980 else if (lpPublished->header().seq != lpClosed->header().seq)
2982 info[jss::published_ledger] = lpPublished->header().seq;
2988 info[jss::jq_trans_overflow] =
2991 info[jss::peer_disconnects_resources] =
2996 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
3000 for (
auto const& port :
registry_.get().getServerHandler().setup().ports)
3004 !(port.adminNetsV4.empty() && port.adminNetsV6.empty() && port.adminUser.empty() &&
3005 port.adminPassword.empty()))
3020 for (
auto const& p : proto)
3021 jv[jss::protocol].
append(p);
3027 auto const& grpcSection =
3029 auto const optPort = grpcSection.get(
Keys::kPort);
3030 if (optPort && grpcSection.get(
Keys::kIp))
3033 jv[jss::port] = *optPort;
3035 jv[jss::protocol].
append(
"grpc");
3038 info[jss::ports] = std::move(ports);
3047 registry_.get().getInboundLedgers().clearFailures();
3053 return registry_.get().getInboundLedgers().getInfo();
3083 [&](
json::Value const& jv) { p->send(jv, true); });
3103 registry_.get().getAcceptedLedgerCache().fetch(lpAccepted->header().hash);
3107 registry_.get().getAcceptedLedgerCache().canonicalizeReplaceClient(
3108 lpAccepted->header().hash, alpAccepted);
3112 alpAccepted->getLedger().get() == lpAccepted.
get(),
3113 "xrpl::NetworkOPsImp::pubLedger : accepted input");
3116 JLOG(
journal_.debug()) <<
"Publishing ledger " << lpAccepted->header().seq <<
" "
3117 << lpAccepted->header().hash;
3125 jvObj[jss::type] =
"ledgerClosed";
3126 jvObj[jss::ledger_index] = lpAccepted->header().seq;
3127 jvObj[jss::ledger_hash] =
to_string(lpAccepted->header().hash);
3128 jvObj[jss::ledger_time] =
3131 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
3133 if (!lpAccepted->rules().enabled(featureXRPFees))
3135 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
3136 jvObj[jss::reserve_base] = lpAccepted->fees().reserve.jsonClipped();
3137 jvObj[jss::reserve_inc] = lpAccepted->fees().increment.jsonClipped();
3139 jvObj[jss::txn_count] =
json::UInt(alpAccepted->size());
3143 jvObj[jss::validated_ledgers] =
3144 registry_.get().getLedgerMaster().getCompleteLedgers();
3153 p->send(jvObj,
true);
3173 p->send(jvObj,
true);
3184 static bool kFirstTime =
true;
3191 for (
auto& inner : outer.second)
3193 auto& subInfo = inner.second;
3194 if (subInfo.index->separationLedgerSeq == 0)
3205 for (
auto const& accTx : *alpAccepted)
3207 JLOG(
journal_.trace()) <<
"pubAccepted: " << accTx->getJson();
3216 registry_.get().getOpenLedger().current()->fees().base,
3249 for (
auto const& [_, subs] :
subBook_)
3250 total += subs.size();
3270 jvObj[jss::type] =
"transaction";
3285 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
3286 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
3288 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
3289 uint32_t netID =
registry_.get().getNetworkIDService().getNetworkID();
3290 if (transaction->isFieldPresent(sfNetworkID))
3291 netID = transaction->getFieldU32(sfNetworkID);
3295 jvObj[jss::ctid] = *ctid;
3297 if (!ledger->open())
3298 jvObj[jss::ledger_hash] =
to_string(ledger->header().hash);
3302 jvObj[jss::ledger_index] = ledger->header().seq;
3303 jvObj[jss::transaction][jss::date] = ledger->header().closeTime.time_since_epoch().count();
3304 jvObj[jss::validated] =
true;
3305 jvObj[jss::close_time_iso] =
toStringIso(ledger->header().closeTime);
3311 jvObj[jss::validated] =
false;
3312 jvObj[jss::ledger_current_index] = ledger->header().seq;
3315 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3316 jvObj[jss::engine_result] = sToken;
3317 jvObj[jss::engine_result_code] = result;
3318 jvObj[jss::engine_result_message] = sHuman;
3320 if (transaction->getTxnType() == ttOFFER_CREATE)
3322 auto const account = transaction->getAccountID(sfAccount);
3323 auto const amount = transaction->getFieldAmount(sfTakerGets);
3326 if (account != amount.getIssuer())
3335 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3344 RPC::insertDeliverMax(jvTx[jss::transaction], transaction->getTxnType(), Version);
3346 if constexpr (Version > 1)
3348 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3349 jvTx[jss::hash] = hash;
3353 jvTx[jss::transaction][jss::hash] = hash;
3366 auto const& stTxn = transaction.
getTxn();
3370 auto const trResult = transaction.
getResult();
3385 [&](
json::Value const& jv) { p->send(jv, true); });
3404 [&](
json::Value const& jv) { p->send(jv, true); });
3452 listeners.
reserve(books.size());
3458 for (
auto const& book : books)
3464 for (
auto sit = it->second.begin(); sit != it->second.end();)
3466 if (
auto p = sit->second.lock())
3473 if (seen.
emplace(p->getSeq()).second)
3480 <<
"pubBookTransaction: pruning expired weak_ptr for seq=" << sit->first;
3481 sit = it->second.erase(sit);
3485 if (it->second.empty())
3490 for (
auto const& p : listeners)
3492 jvObj.
visit(p->getApiVersion(), [&](
json::Value const& jv) { p->send(jv, true); });
3509 auto const currLedgerSeq = ledger->seq();
3515 for (
auto const& affectedAccount : transaction.
getAffected())
3520 auto it = simiIt->second.begin();
3522 while (it != simiIt->second.end())
3534 it = simiIt->second.erase(it);
3541 auto it = simiIt->second.begin();
3542 while (it != simiIt->second.end())
3554 it = simiIt->second.erase(it);
3562 auto& subs = historyIt->second;
3563 auto it = subs.begin();
3564 while (it != subs.end())
3567 if (currLedgerSeq <= info.index->separationLedgerSeq)
3581 it = subs.erase(it);
3591 JLOG(
journal_.trace()) <<
"pubAccountTransaction: "
3592 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3594 if (!notify.
empty() || !accountHistoryNotify.
empty())
3596 auto const& stTxn = transaction.
getTxn();
3600 auto const trResult = transaction.
getResult();
3606 isrListener->getApiVersion(),
3607 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3611 jvObj.
set(jss::account_history_boundary,
true);
3614 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3615 "xrpl::NetworkOPsImp::pubAccountTransaction : "
3616 "account_history_tx_stream not set");
3617 for (
auto& info : accountHistoryNotify)
3619 auto& index = info.index;
3620 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3621 jvObj.
set(jss::account_history_tx_first,
true);
3623 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3626 info.sink->getApiVersion(),
3627 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3651 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3656 auto it = simiIt->second.begin();
3658 while (it != simiIt->second.end())
3670 it = simiIt->second.erase(it);
3678 JLOG(
journal_.trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3680 if (!notify.
empty() || !accountHistoryNotify.
empty())
3688 isrListener->getApiVersion(),
3689 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3693 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3694 "xrpl::NetworkOPs::pubProposedAccountTransaction : "
3695 "account_history_tx_stream not set");
3696 for (
auto& info : accountHistoryNotify)
3698 auto& index = info.index;
3699 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3700 jvObj.
set(jss::account_history_tx_first,
true);
3701 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3703 info.sink->getApiVersion(),
3704 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3721 for (
auto const& naAccountID : vnaAccountIDs)
3723 JLOG(
journal_.trace()) <<
"subAccount: account: " <<
toBase58(naAccountID);
3725 isrListener->insertSubAccountInfo(naAccountID, rt);
3730 for (
auto const& naAccountID : vnaAccountIDs)
3732 auto simIterator = subMap.
find(naAccountID);
3733 if (simIterator == subMap.
end())
3737 usisElement[isrListener->getSeq()] = isrListener;
3739 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3744 simIterator->second[isrListener->getSeq()] = isrListener;
3755 for (
auto const& naAccountID : vnaAccountIDs)
3758 isrListener->deleteSubAccountInfo(naAccountID, rt);
3775 for (
auto const& naAccountID : vnaAccountIDs)
3777 auto simIterator = subMap.
find(naAccountID);
3779 if (simIterator != subMap.
end())
3782 simIterator->second.erase(uSeq);
3784 if (simIterator->second.empty())
3787 subMap.
erase(simIterator);
3797 auto const& accountId = subInfo.
index->accountId;
3798 auto& lastLedgerSeq = subInfo.
index->historyLastLedgerSeq;
3799 auto& txHistoryIndex = subInfo.
index->historyTxIndex;
3801 JLOG(
journal_.trace()) <<
"AccountHistory job for account " <<
toBase58(accountId)
3802 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
3812 auto stx = tx->getSTransaction();
3813 if (stx->getAccountID(sfAccount) == accountId && stx->getSeqValue() == 1)
3817 for (
auto& node : meta->getNodes())
3819 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
3822 if (node.isFieldPresent(sfNewFields))
3824 if (
auto inner =
dynamic_cast<STObject const*
>(node.peekAtPField(sfNewFields));
3827 if (inner->isFieldPresent(sfAccount) &&
3828 inner->getAccountID(sfAccount) == accountId)
3839 auto send = [&](
json::Value const& jvObj,
bool unsubscribe) ->
bool {
3842 sptr->send(jvObj,
true);
3851 auto sendMultiApiJson = [&](
MultiApiJson const& jvObj,
bool unsubscribe) ->
bool {
3855 sptr->getApiVersion(),
3856 [&](
json::Value const& jv) { sptr->send(jv, true); });
3872 auto& db =
registry_.get().getRelationalDatabase();
3874 .account = accountId,
3875 .ledgerRange = {.min = minLedger, .max = maxLedger},
3879 return db.newestAccountTxPage(options);
3885 while (lastLedgerSeq >= 2 && !subInfo.
index->stopHistorical)
3887 int feeChargeCount = 0;
3896 <<
"AccountHistory job for account " <<
toBase58(accountId)
3897 <<
" no InfoSub. Fee charged " << feeChargeCount <<
" times.";
3902 auto startLedgerSeq = (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
3904 <<
"AccountHistory job for account " <<
toBase58(accountId)
3905 <<
", working on ledger range [" << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3907 auto haveRange = [&]() ->
bool {
3910 auto haveSomeValidatedLedgers =
3911 registry_.get().getLedgerMaster().getValidatedRange(validatedMin, validatedMax);
3913 return haveSomeValidatedLedgers && validatedMin <= startLedgerSeq &&
3914 lastLedgerSeq <= validatedMax;
3919 JLOG(
journal_.debug()) <<
"AccountHistory reschedule job for account "
3920 <<
toBase58(accountId) <<
", incomplete ledger range ["
3921 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3927 while (!subInfo.
index->stopHistorical)
3929 auto dbResult = getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
3931 auto const& txns = dbResult.first;
3932 marker = dbResult.second;
3933 size_t const numTxns = txns.size();
3934 for (
size_t i = 0; i < numTxns; ++i)
3936 auto const& [tx, meta] = txns[i];
3940 JLOG(
journal_.debug()) <<
"AccountHistory job for account "
3941 <<
toBase58(accountId) <<
" empty tx or meta.";
3946 registry_.get().getLedgerMaster().getLedgerBySeq(tx->getLedger());
3951 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
3952 "getLedgerBySeq failed");
3953 JLOG(
journal_.debug()) <<
"AccountHistory job for account "
3954 <<
toBase58(accountId) <<
" no ledger.";
3964 "NetworkOPsImp::addAccountHistoryJob : "
3965 "getSTransaction failed");
3966 JLOG(
journal_.debug()) <<
"AccountHistory job for account "
3967 <<
toBase58(accountId) <<
" getSTransaction failed.";
3974 auto const trR = meta->getResultTER();
3977 jvTx.
set(jss::account_history_tx_index, txHistoryIndex--);
3978 if (i + 1 == numTxns || txns[i + 1].first->getLedger() != tx->getLedger())
3979 jvTx.
set(jss::account_history_boundary,
true);
3981 if (isFirstTx(tx, meta))
3983 jvTx.
set(jss::account_history_tx_first,
true);
3984 sendMultiApiJson(jvTx,
false);
3986 JLOG(
journal_.trace()) <<
"AccountHistory job for account "
3987 <<
toBase58(accountId) <<
" done, found last tx.";
3991 sendMultiApiJson(jvTx,
false);
3997 <<
"AccountHistory job for account " <<
toBase58(accountId)
3998 <<
" paging, marker=" << marker->ledgerSeq <<
":" << marker->txnSeq;
4006 if (!subInfo.
index->stopHistorical)
4008 lastLedgerSeq = startLedgerSeq - 1;
4009 if (lastLedgerSeq <= 1)
4012 <<
"AccountHistory job for account " <<
toBase58(accountId)
4013 <<
" done, reached genesis ledger.";
4026 subInfo.
index->separationLedgerSeq = ledger->seq();
4027 auto const& accountId = subInfo.
index->accountId;
4029 if (!ledger->exists(accountKeylet))
4031 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
4032 <<
", no need to add AccountHistory job.";
4037 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
4039 if (sleAcct->getFieldU32(sfSequence) == 1)
4042 <<
"subAccountHistoryStart, genesis account " <<
toBase58(accountId)
4043 <<
" does not have tx, no need to add AccountHistory job.";
4051 "xrpl::NetworkOPsImp::subAccountHistoryStart : failed to "
4052 "access genesis account");
4057 subInfo.
index->historyLastLedgerSeq = ledger->seq();
4058 subInfo.
index->haveHistorical =
true;
4060 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, add AccountHistory job: accountId="
4061 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
4069 if (!isrListener->insertSubAccountHistory(accountId))
4071 JLOG(
journal_.debug()) <<
"subAccountHistory, already subscribed to account "
4083 inner.
emplace(isrListener->getSeq(), ahi);
4088 simIterator->second.emplace(isrListener->getSeq(), ahi);
4091 auto const ledger =
registry_.get().getLedgerMaster().getValidatedLedger();
4101 JLOG(
journal_.debug()) <<
"subAccountHistory, no validated ledger yet, delay start";
4114 isrListener->deleteSubAccountHistory(account);
4128 auto& subInfoMap = simIterator->second;
4129 auto subInfoIter = subInfoMap.find(seq);
4130 if (subInfoIter != subInfoMap.end())
4132 subInfoIter->second.index->stopHistorical =
true;
4137 simIterator->second.erase(seq);
4138 if (simIterator->second.empty())
4143 JLOG(
journal_.debug()) <<
"unsubAccountHistory, account " <<
toBase58(account)
4144 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
4157 subBook_[book].try_emplace(isrListener->getSeq(), isrListener);
4159 isrListener->insertBookSubscription(book);
4169 isrListener->deleteBookSubscription(book);
4180 bool const erased = it->second.erase(uSeq) != 0u;
4181 if (it->second.empty())
4191 XRPL_ASSERT(
standalone_,
"xrpl::NetworkOPsImp::acceptLedger : is standalone");
4209 jvResult[jss::ledger_index] = lpClosed->header().seq;
4210 jvResult[jss::ledger_hash] =
to_string(lpClosed->header().hash);
4211 jvResult[jss::ledger_time] =
4213 if (!lpClosed->rules().enabled(featureXRPFees))
4215 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
4216 jvResult[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
4217 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
4218 jvResult[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
4223 jvResult[jss::validated_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
4282 auto const& feeTrack =
registry_.get().getFeeTrack();
4283 jvResult[jss::random] =
to_string(uRandom);
4285 jvResult[jss::load_base] = feeTrack.getLoadBase();
4286 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4287 jvResult[jss::hostid] =
getHostId(admin);
4288 jvResult[jss::pubkey_node] =
4394 subRpcMapType::iterator
const it =
rpcSubMap_.find(strUrl);
4425 if (map.contains(pInfo->getSeq()))
4432#ifndef USE_NEW_BOOK_PAGE
4443 unsigned int iLimit,
4452 uint256 uTipIndex = uBookBase;
4454 if (
auto stream =
journal_.trace())
4456 stream <<
"getBookPage:" << book;
4457 stream <<
"getBookPage: uBookBase=" << uBookBase;
4458 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4459 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4464 bool const bGlobalFreeze =
4468 bool bDirectAdvance =
true;
4472 unsigned int uBookEntry = 0;
4475 auto const rate =
transferRate(view, book.out.getIssuer());
4476 auto viewJ =
registry_.get().getJournal(
"View");
4478 while (!bDone && iLimit-- > 0)
4482 bDirectAdvance =
false;
4484 JLOG(
journal_.trace()) <<
"getBookPage: bDirectAdvance";
4486 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4493 sleOfferDir.
reset();
4498 JLOG(
journal_.trace()) <<
"getBookPage: bDone";
4503 uTipIndex = sleOfferDir->key();
4506 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4508 JLOG(
journal_.trace()) <<
"getBookPage: uTipIndex=" << uTipIndex;
4509 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4519 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4520 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4521 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4523 bool firstOwnerOffer(
true);
4525 if (book.out.getIssuer() == uOfferOwnerID)
4529 saOwnerFunds = saTakerGets;
4531 else if (bGlobalFreeze)
4535 saOwnerFunds.
clear(book.out);
4539 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4540 if (umBalanceEntry != umBalance.
end())
4544 saOwnerFunds = umBalanceEntry->second;
4545 firstOwnerOffer =
false;
4559 if (saOwnerFunds < beast::kZero)
4563 saOwnerFunds.
clear();
4571 STAmount saOwnerFundsLimit = saOwnerFunds;
4576 && uTakerID != book.out.getIssuer()
4578 && book.out.getIssuer() != uOfferOwnerID)
4583 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4586 if (saOwnerFundsLimit >= saTakerGets)
4589 saTakerGetsFunded = saTakerGets;
4595 saTakerGetsFunded = saOwnerFundsLimit;
4597 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4599 saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.
asset()))
4600 .setJson(jvOffer[jss::taker_pays_funded]);
4607 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4611 jvOf[jss::quality] = saDirRate.
getText();
4613 if (firstOwnerOffer)
4614 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4618 JLOG(
journal_.warn()) <<
"Missing offer";
4621 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4623 bDirectAdvance =
true;
4627 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4647 unsigned int iLimit,
4655 MetaView lesActive(lpLedger, tapNONE,
true);
4656 OrderBookIterator obIterator(lesActive, book);
4658 auto const rate =
transferRate(lesActive, book.out.account);
4660 bool const bGlobalFreeze =
4661 lesActive.isGlobalFrozen(book.out.account) || lesActive.isGlobalFrozen(book.in.account);
4663 while (iLimit-- > 0 && obIterator.nextOffer())
4668 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4669 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4670 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4671 STAmount saDirRate = obIterator.getCurrentRate();
4674 if (book.out.account == uOfferOwnerID)
4677 saOwnerFunds = saTakerGets;
4679 else if (bGlobalFreeze)
4683 saOwnerFunds.
clear(book.out);
4687 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4689 if (umBalanceEntry != umBalance.
end())
4693 saOwnerFunds = umBalanceEntry->second;
4699 saOwnerFunds = lesActive.accountHolds(
4705 if (saOwnerFunds.isNegative())
4709 saOwnerFunds.zero();
4716 STAmount saTakerGetsFunded;
4717 STAmount saOwnerFundsLimit = saOwnerFunds;
4718 Rate offerRate = parityRate;
4720 if (rate != parityRate
4722 && uTakerID !=
book.out.account
4724 &&
book.out.account != uOfferOwnerID)
4729 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4732 if (saOwnerFundsLimit >= saTakerGets)
4735 saTakerGetsFunded = saTakerGets;
4740 saTakerGetsFunded = saOwnerFundsLimit;
4742 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
4746 std::min(saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.asset()))
4747 .setJson(jvOffer[jss::taker_pays_funded]);
4750 STAmount saOwnerPays = (parityRate == offerRate)
4752 : std::
min(saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4754 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4756 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
4759 json::Value& jvOf = jvOffers.append(jvOffer);
4760 jvOf[jss::quality] = saDirRate.getText();
4774 auto [counters, mode, start, initialSync] =
accounting_.getCounterData();
4777 counters[
static_cast<std::size_t>(mode)].dur += current;
4780 stats_.disconnectedDuration.set(
4782 stats_.connectedDuration.set(
4784 stats_.syncingDuration.set(
4786 stats_.trackingDuration.set(
4790 stats_.disconnectedTransitions.set(
4792 stats_.connectedTransitions.set(
4794 stats_.syncingTransitions.set(
4796 stats_.trackingTransitions.set(
4834 auto& state = obj[jss::state_accounting][
kStates[i]];
4835 state[jss::transitions] =
std::to_string(counters[i].transitions);
4836 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
4838 obj[jss::server_state_duration_us] =
std::to_string(current.count());
4839 if (initialSync != 0u)
4840 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
4855 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
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 > pointer
std::shared_ptr< InfoSub > const & ref
std::weak_ptr< InfoSub > wptr
A pool of threads to perform work.
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 subLock_.
std::string getHostId(bool forAdmin)
void reportConsensusStateChange(ConsensusPhase phase)
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
void clearNeedNetworkLedger() override
SubInfoMapType subAccount_
hash_map< AccountID, SubMapType > SubInfoMapType
std::size_t const minPeerCount_
std::vector< TransactionStatus > transactions_
std::set< uint256 > pendingValidations_
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
NetworkOPsImp(ServiceRegistry ®istry, NetworkOPs::clock_type &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)
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 unsubAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
hash_map< Book, SubMapType > SubBookMapType
Maps each order book to its current set of subscribers.
bool subManifests(InfoSub::ref ispListener) override
void stateAccounting(json::Value &obj) override
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
DispatchState dispatchState_
hash_map< std::string, InfoSub::pointer > subRpcMapType
ErrorCodeI subAccountHistory(InfoSub::ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
bool subLedger(InfoSub::ref ispListener, json::Value &jvResult) override
void subAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) 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
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
void pubValidation(std::shared_ptr< STValidation > const &val) override
bool subBook(InfoSub::ref ispListener, Book const &) override
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::ref) override
json::Value getConsensusInfo() override
ConsensusPhase lastConsensusPhase_
bool subServer(InfoSub::ref ispListener, json::Value &jvResult, bool admin) override
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
void setMode(OperatingMode om) override
void setAmendmentBlocked() override
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::array< SubMapType, SubTypes::SLastEntry > streamMaps_
bool subConsensus(InfoSub::ref ispListener) override
std::reference_wrapper< ServiceRegistry > registry_
static std::array< char const *, 5 > const kStates
bool unsubLedger(std::uint64_t uListener) override
bool checkLastClosedLedger(Overlay::PeerSequence const &, uint256 &networkClosed)
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 switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
std::optional< PublicKey > const validatorPK_
std::atomic< bool > amendmentBlocked_
void clearAmendmentWarned() override
LedgerMaster & ledgerMaster_
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
void setStandAlone() override
void setNeedNetworkLedger() override
hash_map< std::uint64_t, InfoSub::wptr > SubMapType
std::size_t getBookSubscribersCount() override
Total number of (book, subscriber) entries currently tracked.
bool unsubServer(std::uint64_t uListener) override
void processClusterTimer()
bool unsubConsensus(std::uint64_t uListener) override
void pubManifest(Manifest const &) override
void consensusViewChange() override
boost::asio::steady_timer accountHistoryTxTimer_
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
void setUNLBlocked() override
bool unsubValidations(std::uint64_t uListener) override
bool subPeerStatus(InfoSub::ref ispListener) override
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
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)
bool tryRemoveRpcSub(std::string const &strUrl) override
bool beginConsensus(uint256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
void processHeartbeatTimer()
hash_map< AccountID, hash_map< std::uint64_t, SubAccountHistoryInfoWeak > > SubAccountHistoryMapType
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
void setAmendmentWarned() override
void pubPeerStatus(std::function< json::Value(void)> const &) override
StateAccounting accounting_
SubAccountHistoryMapType subAccountHistory_
bool subValidations(InfoSub::ref ispListener) override
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
bool subRTTransactions(InfoSub::ref ispListener) override
std::atomic< bool > unlBlocked_
bool unsubBookChanges(std::uint64_t uListener) override
void unsubAccountHistory(InfoSub::ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
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
bool subTransactions(InfoSub::ref ispListener) 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
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_
std::recursive_mutex subLock_
boost::asio::steady_timer clusterTimer_
bool unsubPeerStatus(std::uint64_t uListener) override
bool unsubBook(InfoSub::ref ispListener, Book const &) override
Remove a book subscription for a live subscriber.
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
void unsubAccountInternal(std::uint64_t seq, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
bool subBookChanges(InfoSub::ref ispListener) override
Provides server functionality for clients.
beast::AbstractClock< std::chrono::steady_clock > clock_type
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
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.
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.
void insertMPTokenIssuanceID(json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
static constexpr std::integral_constant< unsigned, Version > kApiVersion
void insertNFTSyntheticInJson(json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
void insertDeliveredAmount(json::Value &meta, ReadView const &, std::shared_ptr< STTx const > const &serializedTx, TxMeta const &)
Add a delivered_amount field to the meta input/output parameter.
Charge const kFeeMediumBurdenRpc
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
std::string const & getCommitHash()
std::string const & getBuildBranch()
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 offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
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.
@ 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.
@ 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.
@ SigBad
Signature is bad. Didn't do local checks.
@ 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::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)
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
std::uint64_t getQuality(uint256 const &uBase)
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::unordered_set< Value, Hash, Pred, Allocator > hash_set
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.
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)
json::Value rpcError(ErrorCodeI iError)
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Check if the issuer has the global freeze flag set.
STAmount amountFromQuality(std::uint64_t rate)
void forAllApiVersions(Fn const &fn, Args &&... args)
bool isTefFailure(TER x) noexcept
std::unique_ptr< LocalTxs > makeLocalTxs()
hash_set< Book > affectedBooks(AcceptedLedgerTx const &alTx, beast::Journal const &j)
Extract the set of books affected by a transaction.
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
std::unique_ptr< NetworkOPs > makeNetworkOPs(ServiceRegistry ®istry, NetworkOPs::clock_type &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)
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.
AccountID calcAccountID(PublicKey const &pk)
uint256 getBookBase(Book const &book)
static std::array< char const *, 5 > const kStateNames
constexpr auto kMuldivMax
std::unordered_map< Key, Value, Hash, Pred, Allocator > hash_map
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isTelLocal(TER x) noexcept
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.
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)
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.
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.
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)
CanonicalTXSet OrderedTxs
detail::MultiApiJson< RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion > MultiApiJson
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
Stats(Handler const &handler, beast::insight::Collector::ptr const &collector)
beast::insight::Gauge trackingTransitions
beast::insight::Gauge fullDuration
beast::insight::Gauge syncingDuration
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.
Data format for exchanging consumption information across peers.
std::vector< Item > items
static constexpr auto kPortGrpc
Sends a message to all peers.
Changes in trusted nodes after updating validator list.
hash_set< 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
T time_since_epoch(T... args)