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/DeliveredAmount.h>
32#include <xrpld/rpc/MPTokenIssuanceID.h>
33#include <xrpld/rpc/ServerHandler.h>
35#include <xrpl/basics/Log.h>
36#include <xrpl/basics/ToString.h>
37#include <xrpl/basics/UnorderedContainers.h>
38#include <xrpl/basics/UptimeClock.h>
39#include <xrpl/basics/base_uint.h>
40#include <xrpl/basics/chrono.h>
41#include <xrpl/basics/contract.h>
42#include <xrpl/basics/mulDiv.h>
43#include <xrpl/basics/safe_cast.h>
44#include <xrpl/basics/scope.h>
45#include <xrpl/basics/strHex.h>
46#include <xrpl/beast/clock/abstract_clock.h>
47#include <xrpl/beast/insight/Collector.h>
48#include <xrpl/beast/insight/Gauge.h>
49#include <xrpl/beast/insight/Hook.h>
50#include <xrpl/beast/net/IPEndpoint.h>
51#include <xrpl/beast/utility/Zero.h>
52#include <xrpl/beast/utility/instrumentation.h>
53#include <xrpl/beast/utility/rngfill.h>
54#include <xrpl/config/Constants.h>
55#include <xrpl/consensus/ConsensusParms.h>
56#include <xrpl/consensus/ConsensusTypes.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>
184 "xrpl::NetworkOPsImp::TransactionStatus::TransactionStatus : "
292 return !(*
this != b);
311 boost::asio::io_context& ioCtx,
328 registry.getInboundTransactions(),
329 beast::getAbstractClock<
std::chrono::steady_clock>(),
333 validatorKeys.keys ? validatorKeys.keys->publicKey : decltype(
validatorPK_){})
335 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
523 getServerInfo(
bool human,
bool admin,
bool counters)
override;
551 TER result)
override;
680 catch (boost::system::system_error
const& e)
682 JLOG(
journal_.error()) <<
"NetworkOPs: heartbeatTimer cancel error: " << e.what();
689 catch (boost::system::system_error
const& e)
691 JLOG(
journal_.error()) <<
"NetworkOPs: clusterTimer cancel error: " << e.what();
698 catch (boost::system::system_error
const& e)
701 <<
"NetworkOPs: accountHistoryTxTimer cancel error: " << e.what();
705 using namespace std::chrono_literals;
715 boost::asio::steady_timer& timer,
895 template <
typename OuterMap,
typename BeforeErase>
901 BeforeErase&& beforeErase);
1027 template <
class Handler>
1029 :
hook(collector->makeHook(handler))
1031 collector->makeGauge(
"State_Accounting",
"Disconnected_duration"))
1032 ,
connectedDuration(collector->makeGauge(
"State_Accounting",
"Connected_duration"))
1033 ,
syncingDuration(collector->makeGauge(
"State_Accounting",
"Syncing_duration"))
1034 ,
trackingDuration(collector->makeGauge(
"State_Accounting",
"Tracking_duration"))
1035 ,
fullDuration(collector->makeGauge(
"State_Accounting",
"Full_duration"))
1037 collector->makeGauge(
"State_Accounting",
"Disconnected_transitions"))
1039 collector->makeGauge(
"State_Accounting",
"Connected_transitions"))
1040 ,
syncingTransitions(collector->makeGauge(
"State_Accounting",
"Syncing_transitions"))
1042 ,
fullTransitions(collector->makeGauge(
"State_Accounting",
"Full_transitions"))
1071 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
1131 static std::string const kHostname = boost::asio::ip::host_name();
1138 static std::string const kShroudedHostId = [
this]() {
1139 auto const&
id =
registry_.get().getApp().nodeIdentity();
1144 return kShroudedHostId;
1153 if (
registry_.get().getCluster().size() != 0)
1159 boost::asio::steady_timer& timer,
1165 if (
auto optionalCountedHandler =
1167 if ((e.value() == boost::system::errc::success) && (!jobQueue_.isStopped()))
1172 if (e.value() != boost::system::errc::success &&
1173 e.value() != boost::asio::error::operation_aborted)
1176 JLOG(journal_.error())
1177 <<
"Timer got error '" << e.message() <<
"'. Restarting timer.";
1182 timer.expires_after(expiryTime);
1183 timer.async_wait(std::move(*optionalCountedHandler));
1194 jobQueue_.addJob(JtNetopTimer,
"NetHeart", [this]() { processHeartbeatTimer(); });
1196 [
this]() { setHeartbeatTimer(); });
1202 using namespace std::chrono_literals;
1216 JLOG(
journal_.debug()) <<
"Scheduling AccountHistory job for account "
1218 using namespace std::chrono_literals;
1246 ss <<
"Node count (" << numPeers <<
") has fallen "
1249 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
1253 CLOG(clog.
ss()) <<
"already DISCONNECTED. too few peers (" << numPeers
1269 JLOG(
journal_.info()) <<
"Node count (" << numPeers <<
") is sufficient.";
1270 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers <<
" peers. ";
1275 auto origMode =
mode_.load();
1285 auto newMode =
mode_.load();
1286 if (origMode != newMode)
1290 CLOG(clog.
ss()) <<
". ";
1303 CLOG(clog.
ss()) <<
". ";
1311 if (
registry_.get().getCluster().size() == 0)
1314 using namespace std::chrono_literals;
1316 bool const update =
registry_.get().getCluster().update(
1317 registry_.get().getApp().nodeIdentity().first,
1320 ?
registry_.get().getFeeTrack().getLocalFee()
1326 JLOG(
journal_.debug()) <<
"Too soon to send cluster update";
1331 protocol::TMCluster cluster;
1333 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1338 n.set_nodename(node.
name());
1342 for (
auto& item : gossip.
items)
1344 protocol::TMLoadSource& node = *cluster.add_loadsources();
1346 node.set_cost(item.balance);
1360 auto const consensusMode =
consensus_.mode();
1367 return "validating";
1387 JLOG(
journal_.error()) <<
"Submitted transaction invalid: tfInnerBatchTxn flag present.";
1394 auto const txid = trans->getTransactionID();
1395 auto const flags =
registry_.get().getHashRouter().getFlags(txid);
1399 JLOG(
journal_.warn()) <<
"Submitted transaction cached bad";
1410 JLOG(
journal_.warn()) <<
"Submitted transaction invalid: " << reason;
1416 JLOG(
journal_.warn()) <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1434 auto const newFlags =
registry_.get().getHashRouter().getFlags(transaction->getID());
1439 JLOG(
journal_.warn()) << transaction->getID() <<
": cached bad!\n";
1450 auto const sttx = *transaction->getSTransaction();
1462 auto const [validity, reason] =
1465 validity ==
Validity::Valid,
"xrpl::NetworkOPsImp::processTransaction : valid validity");
1470 JLOG(
journal_.info()) <<
"Transaction has bad signature: " << reason;
1478 registry_.get().getMasterTransaction().canonicalize(&transaction);
1514 if (transaction->getApplying())
1517 transactions_.emplace_back(transaction, bUnlimited,
false, failType);
1518 transaction->setApplying();
1522 if (
jobQueue_.addJob(
JtBatch,
"TxBatchAsync", [
this]() { transactionBatch(); }))
1537 if (!transaction->getApplying())
1539 transactions_.emplace_back(transaction, bUnlimited,
true, failType);
1540 transaction->setApplying();
1544 return transaction->getApplying();
1567 if (
jobQueue_.addJob(
JtBatch,
"TxBatchSync", [
this]() { transactionBatch(); }))
1573 }
while (retryCallback(lock));
1582 for (
auto const& [_, tx] :
set)
1589 if (!reason.
empty())
1591 JLOG(
journal_.trace()) <<
"Exception checking transaction: " << reason;
1609 for (
auto& transaction : candidates)
1611 if (!transaction->getApplying())
1614 transaction->setApplying();
1630 JLOG(
journal_.debug()) <<
"No transaction to process!";
1635 XRPL_ASSERT(lock.owns_lock(),
"xrpl::NetworkOPsImp::processTransactionSet has lock");
1637 transactions_, [](
auto const& t) {
return t.transaction->getApplying(); });
1661 XRPL_ASSERT(!
transactions.empty(),
"xrpl::NetworkOPsImp::apply : non-empty transactions");
1671 bool changed =
false;
1686 auto const result =
registry_.get().getTxQ().apply(
1687 registry_.get().getApp(), view, e.transaction->getSTransaction(), flags, j);
1688 e.result = result.ter;
1689 e.applied = result.applied;
1690 changed = changed || result.applied;
1700 validatedLedgerIndex = l->header().seq;
1702 auto newOL =
registry_.get().getOpenLedger().current();
1705 e.transaction->clearSubmitResult();
1710 e.transaction->setApplied();
1713 e.transaction->setResult(e.result);
1717 registry_.get().getHashRouter().setFlags(
1728 JLOG(
journal_.info()) <<
"TransactionResult: " << token <<
": " << human;
1733 bool const addLocal = e.local;
1737 JLOG(
journal_.debug()) <<
"Transaction is now included in open ledger";
1743 auto const& txCur = e.transaction->getSTransaction();
1755 if (t->getApplying())
1766 JLOG(
journal_.info()) <<
"Transaction is obsolete";
1771 JLOG(
journal_.debug()) <<
"Transaction is likely to claim a"
1772 <<
" fee, but is queued until fee drops";
1779 e.transaction->setQueued();
1780 e.transaction->setKept();
1786 auto const lastLedgerSeq =
1787 e.transaction->getSTransaction()->at(~sfLastLedgerSequence);
1788 auto const ledgersLeft = lastLedgerSeq
1808 registry_.get().getHashRouter().setFlags(
1812 JLOG(
journal_.debug()) <<
"Transaction should be held: " << e.result;
1815 e.transaction->setKept();
1820 <<
"Not holding transaction " << e.transaction->getID() <<
": "
1821 << (e.local ?
"local" :
"network") <<
", "
1822 <<
"result: " << e.result <<
" ledgers left: "
1823 << (ledgersLeft ?
to_string(*ledgersLeft) :
"unspecified");
1829 JLOG(
journal_.debug()) <<
"Status other than success " << e.result;
1835 if (addLocal && !enforceFailHard)
1838 ledgerMaster_.getCurrentLedgerIndex(), e.transaction->getSTransaction());
1839 e.transaction->setKept();
1848 registry_.get().getHashRouter().shouldRelay(e.transaction->getID());
1849 if (
auto const sttx = *(e.transaction->getSTransaction()); toSkip &&
1856 protocol::TMTransaction tx;
1860 tx.set_rawtransaction(s.
data(), s.
size());
1861 tx.set_status(protocol::tsCURRENT);
1862 tx.set_receivetimestamp(
1863 registry_.get().getTimeKeeper().now().time_since_epoch().count());
1866 registry_.get().getOverlay().relay(e.transaction->getID(), tx, *toSkip);
1867 e.transaction->setBroadcast();
1871 if (validatedLedgerIndex)
1873 auto [fee, accountSeq, availableSeq] =
1874 registry_.get().getTxQ().getTxRequiredFeeAndSeq(
1875 *newOL, e.transaction->getSTransaction());
1876 e.transaction->setCurrentLedgerState(
1877 *validatedLedgerIndex, fee, accountSeq, availableSeq);
1885 e.transaction->clearApplying();
1887 if (!submitHeld.
empty())
1896 for (
auto& e : submitHeld)
1922 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1925 XRPL_ASSERT(sleCur,
"xrpl::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1927 switch (sleCur->getType())
1930 if (!jvObjects.
isMember(jss::offers))
1936 case ltRIPPLE_STATE:
1937 if (!jvObjects.
isMember(jss::ripple_lines))
1942 jvObjects[jss::ripple_lines].
append(
1946 case ltACCOUNT_ROOT:
1951 "xrpl::NetworkOPsImp::getOwnerInfo : invalid "
1958 uNodeDir = sleNode->getFieldU64(sfIndexNext);
1963 XRPL_ASSERT(sleNode,
"xrpl::NetworkOPsImp::getOwnerInfo : read next page");
1965 }
while (uNodeDir != 0u);
2039 JLOG(
journal_.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
2046 uint256 closedLedger = ourClosed->header().hash;
2047 uint256 const prevClosedLedger = ourClosed->header().parentHash;
2048 JLOG(
journal_.trace()) <<
"OurClosed: " << closedLedger;
2049 JLOG(
journal_.trace()) <<
"PrevClosed: " << prevClosedLedger;
2054 auto& validations =
registry_.get().getValidations();
2059 peerCounts[closedLedger] = 0;
2061 peerCounts[closedLedger]++;
2063 for (
auto& peer : peerList)
2065 uint256 const peerLedger = peer->getClosedLedgerHash();
2068 ++peerCounts[peerLedger];
2071 for (
auto const& it : peerCounts)
2072 JLOG(
journal_.debug()) <<
"L: " << it.first <<
" n=" << it.second;
2074 uint256 const preferredLCL = validations.getPreferredLCL(
2079 bool switchLedgers = preferredLCL != closedLedger;
2081 closedLedger = preferredLCL;
2083 if (switchLedgers && (closedLedger == prevClosedLedger))
2086 JLOG(
journal_.info()) <<
"We won't switch to our own previous ledger";
2087 networkClosed = ourClosed->header().hash;
2088 switchLedgers =
false;
2092 networkClosed = closedLedger;
2098 auto consensus =
ledgerMaster_.getLedgerByHash(closedLedger);
2102 consensus =
registry_.get().getInboundLedgers().acquire(
2112 networkClosed = ourClosed->header().hash;
2116 JLOG(
journal_.warn()) <<
"We are not running on the consensus ledger";
2117 JLOG(
journal_.info()) <<
"Our LCL: " << ourClosed->header().hash <<
getJson({*ourClosed, {}});
2118 JLOG(
journal_.info()) <<
"Net LCL " << closedLedger;
2140 JLOG(
journal_.error()) <<
"JUMP last closed ledger to " << newLCL->header().hash;
2145 registry_.get().getTxQ().processClosedLedger(
registry_.get().getApp(), *newLCL,
true);
2152 auto retries =
localTX_->getTxSet();
2153 auto const lastVal =
registry_.get().getLedgerMaster().getValidatedLedger();
2180 protocol::TMStatusChange s;
2181 s.set_newevent(protocol::neSWITCHED_LEDGER);
2182 s.set_ledgerseq(newLCL->header().seq);
2183 s.set_networktime(
registry_.get().getTimeKeeper().now().time_since_epoch().count());
2184 s.set_ledgerhashprevious(
2185 newLCL->header().parentHash.begin(), newLCL->header().parentHash.size());
2186 s.set_ledgerhash(newLCL->header().hash.begin(), newLCL->header().hash.size());
2196 XRPL_ASSERT(networkClosed.
isNonZero(),
"xrpl::NetworkOPsImp::beginConsensus : nonzero input");
2198 auto closingInfo =
ledgerMaster_.getCurrentLedger()->header();
2200 JLOG(
journal_.info()) <<
"Consensus time for #" << closingInfo.seq <<
" with LCL "
2201 << closingInfo.parentHash;
2203 auto prevLedger =
ledgerMaster_.getLedgerByHash(closingInfo.parentHash);
2210 JLOG(
journal_.warn()) <<
"Don't have LCL, going to tracking";
2212 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
2215 CLOG(clog) <<
"beginConsensus no previous ledger. ";
2220 prevLedger->header().hash == closingInfo.parentHash,
2221 "xrpl::NetworkOPsImp::beginConsensus : prevLedger hash matches "
2224 closingInfo.parentHash ==
ledgerMaster_.getClosedLedger()->header().hash,
2225 "xrpl::NetworkOPsImp::beginConsensus : closedLedger parent matches "
2228 registry_.get().getValidators().setNegativeUNL(prevLedger->negativeUNL());
2230 registry_.get().getValidations().getCurrentNodeIDs(),
2231 closingInfo.parentCloseTime,
2236 if (!changes.
added.empty() || !changes.
removed.empty())
2240 registry_.get().getAmendmentTable().trustChanged(
2241 registry_.get().getValidators().getQuorumKeys().second);
2245 registry_.get().getTimeKeeper().closeTime(),
2259 JLOG(
journal_.debug()) <<
"Initiating consensus engine";
2266 auto const& peerKey = peerPos.
publicKey();
2278 JLOG(
journal_.error()) <<
"Received a proposal signed by MY KEY from a peer. This may "
2279 "indicate a misconfiguration where another node has the same "
2280 "validator key, or may be caused by unusual message routing and "
2293 protocol::TMHaveTransactionSet msg;
2294 msg.set_hash(map->getHash().asUInt256().begin(), 256 / 8);
2295 msg.set_status(protocol::tsHAVE);
2308 for (
auto const& it :
registry_.get().getOverlay().getActivePeers())
2310 if (it && (it->getClosedLedgerHash() == deadLedger))
2312 JLOG(
journal_.trace()) <<
"Killing obsolete peer status";
2318 bool const ledgerChange =
2321 if (networkClosed.
isZero())
2323 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
2349 if (
registry_.get().getTimeKeeper().now() <
2350 (current->header().parentCloseTime + 2 * current->header().closeTimeResolution))
2384 jvObj[jss::type] =
"manifestReceived";
2390 jvObj[jss::signature] =
strHex(*sig);
2393 jvObj[jss::domain] = mo.
domain;
2398 if (
auto p = i->second.lock())
2400 p->send(jvObj,
true);
2419 ,
em{escalationMetrics}
2433 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2434 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2435 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2469 registry_.get().getOpenLedger().current()->fees().base,
2473 jvObj[jss::type] =
"serverStatus";
2486 jvObj[jss::load_factor] =
trunc32(loadFactor);
2487 jvObj[jss::load_factor_fee_escalation] = f.
em->openLedgerFeeLevel.jsonClipped();
2488 jvObj[jss::load_factor_fee_queue] = f.
em->minProcessingFeeLevel.jsonClipped();
2489 jvObj[jss::load_factor_fee_reference] = f.
em->referenceFeeLevel.jsonClipped();
2507 p->send(jvObj,
true);
2530 if (!streamMap.empty())
2533 jvObj[jss::type] =
"consensusPhase";
2534 jvObj[jss::consensus] =
to_string(phase);
2536 for (
auto i = streamMap.begin(); i != streamMap.end();)
2538 if (
auto p = i->second.lock())
2540 p->send(jvObj,
true);
2546 i = streamMap.erase(i);
2567 auto const signerPublic = val->getSignerPublic();
2569 jvObj[jss::type] =
"validationReceived";
2571 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2572 jvObj[jss::signature] =
strHex(val->getSignature());
2573 jvObj[jss::full] = val->isFull();
2574 jvObj[jss::flags] = val->getFlags();
2575 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2576 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2577 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
2579 if (
auto version = (*val)[~sfServerVersion])
2582 if (
auto cookie = (*val)[~sfCookie])
2585 if (
auto hash = (*val)[~sfValidatedHash])
2586 jvObj[jss::validated_hash] =
strHex(*hash);
2588 auto const masterKey =
registry_.get().getValidatorManifests().getMasterKey(signerPublic);
2590 if (masterKey != signerPublic)
2595 if (
auto const seq = (*val)[~sfLedgerSequence])
2596 jvObj[jss::ledger_index] = *seq;
2598 if (val->isFieldPresent(sfAmendments))
2601 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2605 if (
auto const closeTime = (*val)[~sfCloseTime])
2606 jvObj[jss::close_time] = *closeTime;
2608 if (
auto const loadFee = (*val)[~sfLoadFee])
2609 jvObj[jss::load_fee] = *loadFee;
2611 if (
auto const baseFee = val->at(~sfBaseFee))
2612 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2614 if (
auto const reserveBase = val->at(~sfReserveBase))
2615 jvObj[jss::reserve_base] = *reserveBase;
2617 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2618 jvObj[jss::reserve_inc] = *reserveInc;
2622 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); baseFeeXRP && baseFeeXRP->native())
2623 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2625 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
2626 reserveBaseXRP && reserveBaseXRP->native())
2627 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2629 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
2630 reserveIncXRP && reserveIncXRP->native())
2631 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2640 if (jvTx.
isMember(jss::ledger_index))
2642 jvTx[jss::ledger_index] =
std::to_string(jvTx[jss::ledger_index].asUInt());
2648 if (
auto p = i->second.lock())
2652 [&](
json::Value const& jv) { p->send(jv, true); });
2678 jvObj[jss::type] =
"peerStatusChange";
2686 p->send(jvObj,
true);
2701 using namespace std::chrono_literals;
2704 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() < 1min)
2709 if (
registry_.get().getLedgerMaster().getValidatedLedgerAge() >= 1min)
2730 JLOG(
journal_.trace()) <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2749 JLOG(
journal_.warn()) <<
"Exception thrown for handling new validation "
2750 << val->getLedgerHash() <<
": " << e.
what();
2754 JLOG(
journal_.warn()) <<
"Unknown exception thrown for handling new validation "
2755 << val->getLedgerHash();
2765 JLOG(
journal_.debug()) << [
this, &val]() ->
auto {
2767 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2768 auto master =
registry_.get().getValidators().getTrustedKey(val->getSignerPublic());
2782 return registry_.get().getApp().config().relayUntrustedValidations == 1 || val->isTrusted();
2804 "This server is amendment blocked, and must be updated to be "
2805 "able to stay in sync with the network.";
2812 "This server has an expired validator list. validators.txt "
2813 "may be incorrectly configured or some [validator_list_sites] "
2814 "may be unreachable.";
2821 "One or more unsupported amendments have reached majority. "
2822 "Upgrade to the latest version before they are activated "
2823 "to avoid being amendment blocked.";
2824 if (
auto const expected =
2825 registry_.get().getAmendmentTable().firstUnsupportedExpected())
2828 d[jss::expected_date] = expected->time_since_epoch().count();
2829 d[jss::expected_date_UTC] =
to_string(*expected);
2833 if (warnings.
size() != 0u)
2834 info[jss::warnings] = std::move(warnings);
2842 if (!
registry_.get().getApp().config().serverDomain.empty())
2843 info[jss::server_domain] =
registry_.get().getApp().config().serverDomain;
2853 info[jss::network_ledger] =
"waiting";
2855 info[jss::validation_quorum] =
2863 switch (
registry_.get().getApp().config().nodeSize)
2866 info[jss::node_size] =
"tiny";
2869 info[jss::node_size] =
"small";
2872 info[jss::node_size] =
"medium";
2875 info[jss::node_size] =
"large";
2878 info[jss::node_size] =
"huge";
2882 auto when =
registry_.get().getValidators().expires();
2888 info[jss::validator_list_expires] =
2893 info[jss::validator_list_expires] = 0;
2904 if (*when == TimeKeeper::time_point::max())
2906 x[jss::expiration] =
"never";
2907 x[jss::status] =
"active";
2913 if (*when >
registry_.get().getTimeKeeper().now())
2915 x[jss::status] =
"active";
2919 x[jss::status] =
"expired";
2925 x[jss::status] =
"unknown";
2926 x[jss::expiration] =
"unknown";
2939 info[jss::io_latency_ms] =
2944 if (
auto const localPubKey =
registry_.get().getValidators().localPublicKey();
2945 localPubKey &&
registry_.get().getApp().getValidationPublicKey())
2951 info[jss::pubkey_validator] =
"none";
2957 info[jss::counters] =
registry_.get().getPerfLog().countersJson();
2960 registry_.get().getNodeStore().getCountsJson(nodestore);
2961 info[jss::counters][jss::nodestore] = nodestore;
2962 info[jss::current_activities] =
registry_.get().getPerfLog().currentJson();
2965 info[jss::pubkey_node] =
2968 info[jss::complete_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
2971 info[jss::amendment_blocked] =
true;
2985 lastClose[jss::converge_time_s] =
2993 info[jss::last_close] = lastClose;
3000 if (
auto const netid =
registry_.get().getOverlay().networkID())
3001 info[jss::network_id] =
static_cast<json::UInt>(*netid);
3003 auto const escalationMetrics =
3006 auto const loadFactorServer =
registry_.get().getFeeTrack().getLoadFactor();
3007 auto const loadBaseServer =
registry_.get().getFeeTrack().getLoadBase();
3011 auto const loadFactorFeeEscalation =
mulDiv(
3012 escalationMetrics.openLedgerFeeLevel,
3014 escalationMetrics.referenceFeeLevel)
3017 auto const loadFactor =
3022 info[jss::load_base] = loadBaseServer;
3023 info[jss::load_factor] =
trunc32(loadFactor);
3024 info[jss::load_factor_server] = loadFactorServer;
3031 info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.jsonClipped();
3032 info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.jsonClipped();
3033 info[jss::load_factor_fee_reference] = escalationMetrics.referenceFeeLevel.jsonClipped();
3037 info[jss::load_factor] =
static_cast<double>(loadFactor) / loadBaseServer;
3039 if (loadFactorServer != loadFactor)
3040 info[jss::load_factor_server] =
static_cast<double>(loadFactorServer) / loadBaseServer;
3045 if (fee != loadBaseServer)
3046 info[jss::load_factor_local] =
static_cast<double>(fee) / loadBaseServer;
3047 fee =
registry_.get().getFeeTrack().getRemoteFee();
3048 if (fee != loadBaseServer)
3049 info[jss::load_factor_net] =
static_cast<double>(fee) / loadBaseServer;
3050 fee =
registry_.get().getFeeTrack().getClusterFee();
3051 if (fee != loadBaseServer)
3052 info[jss::load_factor_cluster] =
static_cast<double>(fee) / loadBaseServer;
3054 if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel &&
3055 (admin || loadFactorFeeEscalation != loadFactor))
3057 info[jss::load_factor_fee_escalation] =
3058 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
3059 escalationMetrics.referenceFeeLevel);
3061 if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel)
3063 info[jss::load_factor_fee_queue] =
3064 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
3065 escalationMetrics.referenceFeeLevel);
3083 XRPAmount const baseFee = lpClosed->fees().base;
3085 l[jss::seq] =
json::UInt(lpClosed->header().seq);
3086 l[jss::hash] =
to_string(lpClosed->header().hash);
3091 l[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
3092 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
3093 l[jss::close_time] =
3099 l[jss::reserve_base_xrp] = lpClosed->fees().reserve.decimalXRP();
3100 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
3102 if (
auto const closeOffset =
registry_.get().getTimeKeeper().closeOffset();
3103 std::abs(closeOffset.count()) >= 60)
3104 l[jss::close_time_offset] =
static_cast<std::uint32_t>(closeOffset.count());
3114 auto lCloseTime = lpClosed->header().closeTime;
3115 auto closeTime =
registry_.get().getTimeKeeper().closeTime();
3116 if (lCloseTime <= closeTime)
3118 using namespace std::chrono_literals;
3119 auto age = closeTime - lCloseTime;
3127 info[jss::validated_ledger] = l;
3131 info[jss::closed_ledger] = l;
3137 info[jss::published_ledger] =
"none";
3139 else if (lpPublished->header().seq != lpClosed->header().seq)
3141 info[jss::published_ledger] = lpPublished->header().seq;
3147 info[jss::jq_trans_overflow] =
3150 info[jss::peer_disconnects_resources] =
3155 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
3159 for (
auto const& port :
registry_.get().getServerHandler().setup().ports)
3163 !(port.adminNetsV4.empty() && port.adminNetsV6.empty() && port.adminUser.empty() &&
3164 port.adminPassword.empty()))
3179 for (
auto const& p : proto)
3180 jv[jss::protocol].
append(p);
3186 auto const& grpcSection =
3188 auto const optPort = grpcSection.get(
Keys::kPort);
3189 if (optPort && grpcSection.get(
Keys::kIp))
3192 jv[jss::port] = *optPort;
3194 jv[jss::protocol].
append(
"grpc");
3197 info[jss::ports] = std::move(ports);
3206 registry_.get().getInboundLedgers().clearFailures();
3212 return registry_.get().getInboundLedgers().getInfo();
3248 [&](
json::Value const& jv) { p->send(jv, true); });
3269 registry_.get().getAcceptedLedgerCache().fetch(lpAccepted->header().hash);
3273 registry_.get().getAcceptedLedgerCache().canonicalizeReplaceClient(
3274 lpAccepted->header().hash, alpAccepted);
3278 alpAccepted->getLedger().get() == lpAccepted.
get(),
3279 "xrpl::NetworkOPsImp::pubLedger : accepted input");
3281 JLOG(
journal_.debug()) <<
"Publishing ledger " << lpAccepted->header().seq <<
" "
3282 << lpAccepted->header().hash;
3291 for (
auto const& accTx : *alpAccepted)
3293 JLOG(
journal_.trace()) <<
"pubAccepted: " << accTx->getJson();
3294 bool const last = &*accTx == &alpAccepted->back();
3316 jvObj[jss::type] =
"ledgerClosed";
3317 jvObj[jss::ledger_index] = lpAccepted->header().seq;
3318 jvObj[jss::ledger_hash] =
to_string(lpAccepted->header().hash);
3319 jvObj[jss::ledger_time] =
3322 jvObj[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
3324 if (!lpAccepted->rules().enabled(featureXRPFees))
3326 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
3327 jvObj[jss::reserve_base] = lpAccepted->fees().reserve.jsonClipped();
3328 jvObj[jss::reserve_inc] = lpAccepted->fees().increment.jsonClipped();
3330 jvObj[jss::txn_count] =
json::UInt(alpAccepted->size());
3334 jvObj[jss::validated_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
3342 p->send(jvObj,
true);
3363 p->send(jvObj,
true);
3390 for (
auto& inner : outer.second)
3392 auto& subInfo = inner.second;
3393 if (subInfo.index->separationLedgerSeq == 0)
3403 registry_.get().getOpenLedger().current()->fees().base,
3436 for (
auto const& [_, subs] :
subBook_)
3437 total += subs.size();
3457 jvObj[jss::type] =
"transaction";
3472 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
3473 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
3475 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
3476 uint32_t netID =
registry_.get().getNetworkIDService().getNetworkID();
3477 if (transaction->isFieldPresent(sfNetworkID))
3478 netID = transaction->getFieldU32(sfNetworkID);
3482 jvObj[jss::ctid] = *ctid;
3484 if (!ledger->open())
3485 jvObj[jss::ledger_hash] =
to_string(ledger->header().hash);
3489 jvObj[jss::ledger_index] = ledger->header().seq;
3490 jvObj[jss::transaction][jss::date] = ledger->header().closeTime.time_since_epoch().count();
3491 jvObj[jss::validated] =
true;
3492 jvObj[jss::close_time_iso] =
toStringIso(ledger->header().closeTime);
3498 jvObj[jss::validated] =
false;
3499 jvObj[jss::ledger_current_index] = ledger->header().seq;
3502 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3503 jvObj[jss::engine_result] = sToken;
3504 jvObj[jss::engine_result_code] = result;
3505 jvObj[jss::engine_result_message] = sHuman;
3507 if (transaction->getTxnType() == ttOFFER_CREATE)
3509 auto const account = transaction->getAccountID(sfAccount);
3510 auto const amount = transaction->getFieldAmount(sfTakerGets);
3513 if (account != amount.getIssuer())
3522 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3531 rpc::insertDeliverMax(jvTx[jss::transaction], transaction->getTxnType(), Version);
3533 if constexpr (Version > 1)
3535 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3536 jvTx[jss::hash] = hash;
3540 jvTx[jss::transaction][jss::hash] = hash;
3553 auto const& stTxn = transaction.
getTxn();
3557 auto const trResult = transaction.
getResult();
3578 [&](
json::Value const& jv) { p->send(jv, true); });
3598 [&](
json::Value const& jv) { p->send(jv, true); });
3647 listeners.
reserve(books.size());
3653 for (
auto const& book : books)
3659 for (
auto sit = it->second.begin(); sit != it->second.end();)
3661 if (
auto p = sit->second.lock())
3668 if (seen.
emplace(p->getSeq()).second)
3675 <<
"pubBookTransaction: pruning expired weak_ptr for seq=" << sit->first;
3676 sit = it->second.erase(sit);
3680 if (it->second.empty())
3685 for (
auto const& p : listeners)
3687 jvObj.
visit(p->getApiVersion(), [&](
json::Value const& jv) { p->send(jv, true); });
3704 auto const currLedgerSeq = ledger->seq();
3710 for (
auto const& affectedAccount : transaction.
getAffected())
3715 auto it = simiIt->second.begin();
3717 while (it != simiIt->second.end())
3729 it = simiIt->second.erase(it);
3736 auto it = simiIt->second.begin();
3737 while (it != simiIt->second.end())
3749 it = simiIt->second.erase(it);
3757 auto& subs = historyIt->second;
3758 auto it = subs.begin();
3759 while (it != subs.end())
3762 if (currLedgerSeq <= info.index->separationLedgerSeq)
3776 it = subs.erase(it);
3786 JLOG(
journal_.trace()) <<
"pubAccountTransaction: "
3787 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3789 if (!notify.
empty() || !accountHistoryNotify.
empty())
3791 auto const& stTxn = transaction.
getTxn();
3795 auto const trResult = transaction.
getResult();
3801 isrListener->getApiVersion(),
3802 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3806 jvObj.
set(jss::account_history_boundary,
true);
3809 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3810 "xrpl::NetworkOPsImp::pubAccountTransaction : "
3811 "account_history_tx_stream not set");
3812 for (
auto& info : accountHistoryNotify)
3814 auto& index = info.index;
3815 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3816 jvObj.
set(jss::account_history_tx_first,
true);
3818 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3821 info.sink->getApiVersion(),
3822 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3846 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3851 auto it = simiIt->second.begin();
3853 while (it != simiIt->second.end())
3865 it = simiIt->second.erase(it);
3873 JLOG(
journal_.trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3875 if (!notify.
empty() || !accountHistoryNotify.
empty())
3883 isrListener->getApiVersion(),
3884 [&](
json::Value const& jv) { isrListener->send(jv, true); });
3888 jvObj.
isMember(jss::account_history_tx_stream) == MultiApiJson::IsMemberResult::None,
3889 "xrpl::NetworkOPs::pubProposedAccountTransaction : "
3890 "account_history_tx_stream not set");
3891 for (
auto& info : accountHistoryNotify)
3893 auto& index = info.index;
3894 if (index->forwardTxIndex == 0 && !index->haveHistorical)
3895 jvObj.
set(jss::account_history_tx_first,
true);
3896 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex++);
3898 info.sink->getApiVersion(),
3899 [&](
json::Value const& jv) { info.sink->send(jv, true); });
3916 for (
auto const& naAccountID : vnaAccountIDs)
3918 JLOG(
journal_.trace()) <<
"subAccount: account: " <<
toBase58(naAccountID);
3920 isrListener->insertSubAccountInfo(naAccountID, rt);
3925 for (
auto const& naAccountID : vnaAccountIDs)
3927 auto simIterator = subMap.
find(naAccountID);
3928 if (simIterator == subMap.
end())
3932 usisElement[isrListener->getSeq()] = isrListener;
3934 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3939 simIterator->second[isrListener->getSeq()] = isrListener;
3950 for (
auto const& naAccountID : vnaAccountIDs)
3953 isrListener->deleteSubAccountInfo(naAccountID, rt);
3970 for (
auto const& naAccountID : vnaAccountIDs)
3972 auto simIterator = subMap.
find(naAccountID);
3974 if (simIterator != subMap.
end())
3977 simIterator->second.erase(uSeq);
3979 if (simIterator->second.empty())
3982 subMap.
erase(simIterator);
3988template <
typename OuterMap,
typename BeforeErase>
3994 BeforeErase&& beforeErase)
4001 auto it = accounts.
begin();
4002 auto const end = accounts.
end();
4009 auto outerIter = outerMap.find(*it);
4010 if (outerIter != outerMap.end())
4015 auto innerIter = outerIter->second.find(seq);
4016 if (innerIter != outerIter->second.end())
4017 beforeErase(innerIter->second);
4021 outerIter->second.erase(seq);
4022 if (outerIter->second.empty())
4023 outerMap.erase(outerIter);
4050 info.
index->stopHistorical =
true;
4062 if (rtAccounts.
empty() && normalAccounts.
empty() && historyAccounts.
empty())
4084 rt = std::move(rtAccounts),
4085 normal = std::move(normalAccounts),
4086 history = std::move(historyAccounts)]()
noexcept {
4095 JLOG(
journal_.error()) <<
"SubCleanup[seq=" << seq <<
"]: " << e.
what();
4099 JLOG(
journal_.error()) <<
"SubCleanup[seq=" << seq <<
"]: unknown exception";
4108 auto const& accountId = subInfo.
index->accountId;
4109 auto& lastLedgerSeq = subInfo.
index->historyLastLedgerSeq;
4110 auto& txHistoryIndex = subInfo.
index->historyTxIndex;
4112 JLOG(
journal_.trace()) <<
"AccountHistory job for account " <<
toBase58(accountId)
4113 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
4123 auto stx = tx->getSTransaction();
4124 if (stx->getAccountID(sfAccount) == accountId && stx->getSeqProxy().value() == 1)
4129 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
4132 if (node.isFieldPresent(sfNewFields))
4134 if (auto inner = dynamic_cast<STObject const*>(node.peekAtPField(sfNewFields));
4137 if (inner->isFieldPresent(sfAccount) &&
4138 inner->getAccountID(sfAccount) == accountId)
4148 auto send = [&](
json::Value const& jvObj,
bool unsubscribe) ->
bool {
4151 sptr->send(jvObj,
true);
4160 auto sendMultiApiJson = [&](
MultiApiJson const& jvObj,
bool unsubscribe) ->
bool {
4164 sptr->getApiVersion(),
4165 [&](
json::Value const& jv) { sptr->send(jv, true); });
4181 auto& db =
registry_.get().getRelationalDatabase();
4183 .account = accountId,
4184 .ledgerRange = {.min = minLedger, .max = maxLedger},
4188 .delegate = std::nullopt};
4189 return db.newestAccountTxPage(options);
4195 while (lastLedgerSeq >= 2 && !subInfo.
index->stopHistorical)
4197 int feeChargeCount = 0;
4198 if (auto sptr = subInfo.sinkWptr.lock(); sptr)
4200 sptr->getConsumer().charge(resource::kFeeMediumBurdenRpc);
4205 JLOG(journal_.trace())
4206 <<
"AccountHistory job for account " << toBase58(accountId)
4207 <<
" no InfoSub. Fee charged " << feeChargeCount <<
" times.";
4212 auto startLedgerSeq = (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
4214 <<
"AccountHistory job for account " <<
toBase58(accountId)
4215 <<
", working on ledger range [" << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
4217 auto haveRange = [&]() ->
bool {
4220 auto haveSomeValidatedLedgers =
4221 registry_.get().getLedgerMaster().getValidatedRange(validatedMin, validatedMax);
4223 return haveSomeValidatedLedgers && validatedMin <= startLedgerSeq &&
4224 lastLedgerSeq <= validatedMax;
4229 JLOG(
journal_.debug()) <<
"AccountHistory reschedule job for account "
4230 <<
toBase58(accountId) <<
", incomplete ledger range ["
4231 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
4237 while (!subInfo.
index->stopHistorical)
4239 auto dbResult = getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
4241 auto const& txns = dbResult.first;
4242 marker = dbResult.second;
4243 size_t const numTxns = txns.size();
4244 for (size_t i = 0; i < numTxns; ++i)
4246 auto const& [tx, meta] = txns[i];
4250 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4251 << toBase58(accountId) <<
" empty tx or meta.";
4252 send(rpcError(RpcInternal), true);
4256 registry_.get().getLedgerMaster().getLedgerBySeq(tx->getLedger());
4261 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
4262 "getLedgerBySeq failed");
4263 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4264 << toBase58(accountId) <<
" no ledger.";
4265 send(rpcError(RpcInternal), true);
4269 std::shared_ptr<STTx const> const stTxn = tx->getSTransaction();
4274 "NetworkOPsImp::addAccountHistoryJob : "
4275 "getSTransaction failed");
4276 JLOG(journal_.debug()) <<
"AccountHistory job for account "
4277 << toBase58(accountId) <<
" getSTransaction failed.";
4278 send(rpcError(RpcInternal), true);
4283 auto const ref = std::ref(*meta);
4284 auto const trR = meta->getResultTER();
4285 MultiApiJson jvTx = transJson(stTxn, trR, true, curTxLedger, ref);
4287 jvTx.set(jss::account_history_tx_index, txHistoryIndex--);
4288 if (i + 1 == numTxns || txns[i + 1].first->getLedger() != tx->getLedger())
4289 jvTx.set(jss::account_history_boundary, true);
4291 if (isFirstTx(tx, meta))
4293 jvTx.set(jss::account_history_tx_first, true);
4294 sendMultiApiJson(jvTx, false);
4296 JLOG(journal_.trace()) <<
"AccountHistory job for account "
4297 << toBase58(accountId) <<
" done, found last tx.";
4301 sendMultiApiJson(jvTx, false);
4307 <<
"AccountHistory job for account " <<
toBase58(accountId)
4308 <<
" paging, marker=" << marker->ledgerSeq <<
":" << marker->txnSeq;
4316 if (!subInfo.index->stopHistorical)
4318 lastLedgerSeq = startLedgerSeq - 1;
4319 if (lastLedgerSeq <= 1)
4321 JLOG(journal_.trace())
4322 <<
"AccountHistory job for account " << toBase58(accountId)
4323 <<
" done, reached genesis ledger.";
4336 subInfo.
index->separationLedgerSeq = ledger->seq();
4337 auto const& accountId = subInfo.
index->accountId;
4339 if (!ledger->exists(accountKeylet))
4341 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
4342 <<
", no need to add AccountHistory job.";
4347 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
4349 if (sleAcct->getFieldU32(sfSequence) == 1)
4352 <<
"subAccountHistoryStart, genesis account " <<
toBase58(accountId)
4353 <<
" does not have tx, no need to add AccountHistory job.";
4361 "xrpl::NetworkOPsImp::subAccountHistoryStart : failed to "
4362 "access genesis account");
4367 subInfo.
index->historyLastLedgerSeq = ledger->seq();
4368 subInfo.
index->haveHistorical =
true;
4370 JLOG(
journal_.debug()) <<
"subAccountHistoryStart, add AccountHistory job: accountId="
4371 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
4379 if (!isrListener->insertSubAccountHistory(accountId))
4381 JLOG(
journal_.debug()) <<
"subAccountHistory, already subscribed to account "
4393 inner.
emplace(isrListener->getSeq(), ahi);
4398 simIterator->second.emplace(isrListener->getSeq(), ahi);
4401 auto const ledger =
registry_.get().getLedgerMaster().getValidatedLedger();
4411 JLOG(
journal_.debug()) <<
"subAccountHistory, no validated ledger yet, delay start";
4424 isrListener->deleteSubAccountHistory(account);
4438 auto& subInfoMap = simIterator->second;
4439 auto subInfoIter = subInfoMap.find(seq);
4440 if (subInfoIter != subInfoMap.end())
4442 subInfoIter->second.index->stopHistorical =
true;
4447 simIterator->second.erase(seq);
4448 if (simIterator->second.empty())
4453 JLOG(
journal_.debug()) <<
"unsubAccountHistory, account " <<
toBase58(account)
4454 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
4467 subBook_[book].try_emplace(isrListener->getSeq(), isrListener);
4469 isrListener->insertBookSubscription(book);
4479 isrListener->deleteBookSubscription(book);
4490 bool const erased = it->second.erase(uSeq) != 0u;
4491 if (it->second.empty())
4501 XRPL_ASSERT(
standalone_,
"xrpl::NetworkOPsImp::acceptLedger : is standalone");
4519 jvResult[jss::ledger_index] = lpClosed->header().seq;
4520 jvResult[jss::ledger_hash] =
to_string(lpClosed->header().hash);
4521 jvResult[jss::ledger_time] =
4523 if (!lpClosed->rules().enabled(featureXRPFees))
4525 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
4526 jvResult[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
4527 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
4528 jvResult[jss::network_id] =
registry_.get().getNetworkIDService().getNetworkID();
4533 jvResult[jss::validated_ledgers] =
registry_.get().getLedgerMaster().getCompleteLedgers();
4592 auto const& feeTrack =
registry_.get().getFeeTrack();
4593 jvResult[jss::random] =
to_string(uRandom);
4595 jvResult[jss::load_base] = feeTrack.getLoadBase();
4596 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4597 jvResult[jss::hostid] =
getHostId(admin);
4598 jvResult[jss::pubkey_node] =
4750 if (map.contains(pInfo->getSeq()))
4759#ifndef USE_NEW_BOOK_PAGE
4770 unsigned int iLimit,
4779 uint256 uTipIndex = uBookBase;
4781 if (
auto stream =
journal_.trace())
4783 stream <<
"getBookPage:" << book;
4784 stream <<
"getBookPage: uBookBase=" << uBookBase;
4785 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4786 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4791 bool const bGlobalFreeze =
4795 bool bDirectAdvance =
true;
4799 unsigned int uBookEntry = 0;
4802 auto const rate =
transferRate(view, book.out.getIssuer());
4803 auto viewJ =
registry_.get().getJournal(
"View");
4805 while (!bDone && iLimit-- > 0)
4809 bDirectAdvance =
false;
4811 JLOG(
journal_.trace()) <<
"getBookPage: bDirectAdvance";
4813 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4820 sleOfferDir.
reset();
4825 JLOG(
journal_.trace()) <<
"getBookPage: bDone";
4830 uTipIndex = sleOfferDir->key();
4833 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4835 JLOG(
journal_.trace()) <<
"getBookPage: uTipIndex=" << uTipIndex;
4836 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4846 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4847 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4848 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4850 bool firstOwnerOffer(
true);
4852 if (book.out.getIssuer() == uOfferOwnerID)
4856 saOwnerFunds = saTakerGets;
4858 else if (bGlobalFreeze)
4862 saOwnerFunds.
clear(book.out);
4866 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4867 if (umBalanceEntry != umBalance.
end())
4871 saOwnerFunds = umBalanceEntry->second;
4872 firstOwnerOffer =
false;
4890 saOwnerFunds.
clear();
4898 STAmount saOwnerFundsLimit = saOwnerFunds;
4903 && uTakerID != book.out.getIssuer()
4905 && book.out.getIssuer() != uOfferOwnerID)
4910 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4913 if (saOwnerFundsLimit >= saTakerGets)
4916 saTakerGetsFunded = saTakerGets;
4922 saTakerGetsFunded = saOwnerFundsLimit;
4924 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4926 saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.
asset()))
4927 .setJson(jvOffer[jss::taker_pays_funded]);
4934 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4938 jvOf[jss::quality] = saDirRate.
getText();
4940 if (firstOwnerOffer)
4941 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4945 JLOG(
journal_.warn()) <<
"Missing offer";
4948 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4950 bDirectAdvance =
true;
4954 JLOG(
journal_.trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4974 unsigned int iLimit,
4982 MetaView lesActive(lpLedger, tapNONE,
true);
4983 OrderBookIterator obIterator(lesActive, book);
4985 auto const rate =
transferRate(lesActive, book.out.account);
4987 bool const bGlobalFreeze =
4988 lesActive.isGlobalFrozen(book.out.account) || lesActive.isGlobalFrozen(book.in.account);
4990 while (iLimit-- > 0 && obIterator.nextOffer())
4995 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4996 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4997 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4998 STAmount saDirRate = obIterator.getCurrentRate();
5001 if (book.out.account == uOfferOwnerID)
5004 saOwnerFunds = saTakerGets;
5006 else if (bGlobalFreeze)
5010 saOwnerFunds.
clear(book.out);
5014 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
5016 if (umBalanceEntry != umBalance.
end())
5020 saOwnerFunds = umBalanceEntry->second;
5026 saOwnerFunds = lesActive.accountHolds(
5032 if (saOwnerFunds.isNegative())
5036 saOwnerFunds.zero();
5043 STAmount saTakerGetsFunded;
5044 STAmount saOwnerFundsLimit = saOwnerFunds;
5045 Rate offerRate = parityRate;
5047 if (rate != parityRate
5049 && uTakerID !=
book.out.account
5051 &&
book.out.account != uOfferOwnerID)
5056 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
5059 if (saOwnerFundsLimit >= saTakerGets)
5062 saTakerGetsFunded = saTakerGets;
5067 saTakerGetsFunded = saOwnerFundsLimit;
5069 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
5073 std::min(saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.asset()))
5074 .setJson(jvOffer[jss::taker_pays_funded]);
5077 STAmount saOwnerPays = (parityRate == offerRate)
5079 : std::
min(saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
5081 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
5083 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
5086 json::Value& jvOf = jvOffers.append(jvOffer);
5087 jvOf[jss::quality] = saDirRate.getText();
5101 auto [counters, mode, start, initialSync] =
accounting_.getCounterData();
5104 counters[
static_cast<std::size_t>(mode)].dur += current;
5107 stats_.disconnectedDuration.set(
5109 stats_.connectedDuration.set(
5111 stats_.syncingDuration.set(
5113 stats_.trackingDuration.set(
5117 stats_.disconnectedTransitions.set(
5119 stats_.connectedTransitions.set(
5121 stats_.syncingTransitions.set(
5123 stats_.trackingTransitions.set(
5161 auto& state = obj[jss::state_accounting][
kStates[i]];
5162 state[jss::transitions] =
std::to_string(counters[i].transitions);
5163 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
5165 obj[jss::server_state_duration_us] =
std::to_string(current.count());
5166 if (initialSync != 0u)
5167 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
5182 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 bookLock_.
std::string getHostId(bool forAdmin)
void reportConsensusStateChange(ConsensusPhase phase)
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
void clearNeedNetworkLedger() override
SubInfoMapType subAccount_
hash_map< AccountID, SubMapType > SubInfoMapType
static constexpr std::size_t kAccountCleanupChunk
Maximum number of account entries erased per accountLock_ acquisition during disconnect-time cleanup.
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
void cleanupAccountHistorySubscriptions(std::uint64_t seq, hash_set< AccountID > const &accounts)
Erase one connection's entries from subAccountHistory_ in accountLock_-bounded chunks.
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
void cleanupAccountSubscriptions(std::uint64_t seq, hash_set< AccountID > const &accounts, SubInfoMapType &subMap)
Erase one connection's entries from the given account map (subAccount_ or subRTAccount_) in accountLo...
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
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
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_
One weak_ptr subscriber map per stream type.
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::mutex streamLock_
Guards streamMaps_[] and rpcSubMap_.
std::atomic< bool > amendmentBlocked_
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
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.
std::mutex bookLock_
Guards subBook_.
bool unsubServer(std::uint64_t uListener) override
void processClusterTimer()
bool unsubConsensus(std::uint64_t uListener) override
void pubManifest(Manifest const &) override
std::mutex accountLock_
Guards subAccount_, subRTAccount_, subAccountHistory_.
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 cleanupSubscriptionMap(std::uint64_t seq, hash_set< AccountID > const &accounts, OuterMap &outerMap, BeforeErase &&beforeErase)
Erase one connection's entries from a subscription map in accountLock_-bounded chunks.
void scheduleAccountCleanup(std::uint64_t seq, hash_set< AccountID > rtAccounts, hash_set< AccountID > normalAccounts, hash_set< AccountID > historyAccounts) override
Schedule the server-side teardown of a disconnecting connection's account subscriptions off the destr...
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_
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.
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 child(uint256 const &key) noexcept
Any item that can be in an owner dir.
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.
void insertMPTokenIssuanceID(json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
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.
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 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)
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.
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::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::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.
constexpr Dest safeCast(Src s) noexcept
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
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.
detail::MultiApiJson< rpc::kApiMinimumSupportedVersion, rpc::kApiMaximumValidVersion > MultiApiJson
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
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.
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
Data format for exchanging consumption information across peers.
std::vector< Item > items
T time_since_epoch(T... args)