20 #include <ripple/app/consensus/RCLConsensus.h>
21 #include <ripple/app/consensus/RCLValidations.h>
22 #include <ripple/app/ledger/AcceptedLedger.h>
23 #include <ripple/app/ledger/InboundLedgers.h>
24 #include <ripple/app/ledger/LedgerMaster.h>
25 #include <ripple/app/ledger/LedgerToJson.h>
26 #include <ripple/app/ledger/LocalTxs.h>
27 #include <ripple/app/ledger/OpenLedger.h>
28 #include <ripple/app/ledger/OrderBookDB.h>
29 #include <ripple/app/ledger/TransactionMaster.h>
30 #include <ripple/app/main/LoadManager.h>
31 #include <ripple/app/misc/AmendmentTable.h>
32 #include <ripple/app/misc/HashRouter.h>
33 #include <ripple/app/misc/LoadFeeTrack.h>
34 #include <ripple/app/misc/NetworkOPs.h>
35 #include <ripple/app/misc/Transaction.h>
36 #include <ripple/app/misc/TxQ.h>
37 #include <ripple/app/misc/ValidatorKeys.h>
38 #include <ripple/app/misc/ValidatorList.h>
39 #include <ripple/app/misc/impl/AccountTxPaging.h>
40 #include <ripple/app/rdb/backend/PostgresDatabase.h>
41 #include <ripple/app/rdb/backend/SQLiteDatabase.h>
42 #include <ripple/app/reporting/ReportingETL.h>
43 #include <ripple/app/tx/apply.h>
44 #include <ripple/basics/PerfLog.h>
45 #include <ripple/basics/UptimeClock.h>
46 #include <ripple/basics/mulDiv.h>
47 #include <ripple/basics/safe_cast.h>
48 #include <ripple/beast/rfc2616.h>
49 #include <ripple/beast/utility/rngfill.h>
50 #include <ripple/consensus/Consensus.h>
51 #include <ripple/consensus/ConsensusParms.h>
52 #include <ripple/crypto/RFC1751.h>
53 #include <ripple/crypto/csprng.h>
54 #include <ripple/json/to_string.h>
55 #include <ripple/net/RPCErr.h>
56 #include <ripple/nodestore/DatabaseShard.h>
57 #include <ripple/overlay/Cluster.h>
58 #include <ripple/overlay/Overlay.h>
59 #include <ripple/overlay/predicates.h>
60 #include <ripple/protocol/BuildInfo.h>
61 #include <ripple/protocol/Feature.h>
62 #include <ripple/protocol/STParsedJSON.h>
63 #include <ripple/resource/Fees.h>
64 #include <ripple/resource/ResourceManager.h>
65 #include <ripple/rpc/BookChanges.h>
66 #include <ripple/rpc/DeliveredAmount.h>
67 #include <ripple/rpc/ServerHandler.h>
68 #include <ripple/rpc/impl/RPCHelpers.h>
69 #include <boost/asio/ip/host_name.hpp>
70 #include <boost/asio/steady_timer.hpp>
146 std::chrono::steady_clock::time_point
start_ =
207 return !(*
this != b);
226 boost::asio::io_service& io_svc,
240 app_.logs().journal(
"FeeVote")),
243 app.getInboundTransactions(),
244 beast::get_abstract_clock<
std::chrono::steady_clock>(),
246 app_.logs().journal(
"LedgerConsensus"))
425 getServerInfo(
bool human,
bool admin,
bool counters)
override;
452 TER result)
override;
495 bool historyOnly)
override;
501 bool historyOnly)
override;
569 boost::system::error_code ec;
574 <<
"NetworkOPs: heartbeatTimer cancel error: "
583 <<
"NetworkOPs: clusterTimer cancel error: "
592 <<
"NetworkOPs: accountHistoryTxTimer cancel error: "
597 using namespace std::chrono_literals;
607 boost::asio::steady_timer& timer,
622 const STTx& transaction,
782 template <
class Handler>
784 Handler
const& handler,
786 :
hook(collector->make_hook(handler))
789 "Disconnected_duration"))
792 "Connected_duration"))
794 collector->make_gauge(
"State_Accounting",
"Syncing_duration"))
797 "Tracking_duration"))
799 collector->make_gauge(
"State_Accounting",
"Full_duration"))
802 "Disconnected_transitions"))
805 "Connected_transitions"))
808 "Syncing_transitions"))
811 "Tracking_transitions"))
813 collector->make_gauge(
"State_Accounting",
"Full_transitions"))
842 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
904 static std::string const hostname = boost::asio::ip::host_name();
911 static std::string const shroudedHostId = [
this]() {
917 return shroudedHostId;
932 boost::asio::steady_timer& timer,
939 [
this, onExpire, onError](boost::system::error_code
const& e) {
940 if ((e.value() == boost::system::errc::success) &&
941 (!m_job_queue.isStopped()))
946 if (e.value() != boost::system::errc::success &&
947 e.value() != boost::asio::error::operation_aborted)
950 JLOG(m_journal.error())
951 <<
"Timer got error '" << e.message()
952 <<
"'. Restarting timer.";
957 timer.expires_from_now(expiry_time);
958 timer.async_wait(std::move(*optionalCountedHandler));
969 m_job_queue.addJob(jtNETOP_TIMER,
"NetOPs.heartbeat", [this]() {
970 processHeartbeatTimer();
973 [
this]() { setHeartbeatTimer(); });
977 NetworkOPsImp::setClusterTimer()
979 using namespace std::chrono_literals;
986 processClusterTimer();
989 [
this]() { setClusterTimer(); });
995 JLOG(m_journal.debug()) <<
"Scheduling AccountHistory job for account "
997 using namespace std::chrono_literals;
999 accountHistoryTxTimer_,
1001 [
this, subInfo]() { addAccountHistoryJob(subInfo); },
1002 [
this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
1006 NetworkOPsImp::processHeartbeatTimer()
1015 std::size_t const numPeers = app_.overlay().size();
1018 if (numPeers < minPeerCount_)
1020 if (mMode != OperatingMode::DISCONNECTED)
1022 setMode(OperatingMode::DISCONNECTED);
1023 JLOG(m_journal.warn())
1024 <<
"Node count (" << numPeers <<
") has fallen "
1025 <<
"below required minimum (" << minPeerCount_ <<
").";
1032 setHeartbeatTimer();
1036 if (mMode == OperatingMode::DISCONNECTED)
1038 setMode(OperatingMode::CONNECTED);
1039 JLOG(m_journal.info())
1040 <<
"Node count (" << numPeers <<
") is sufficient.";
1045 if (mMode == OperatingMode::SYNCING)
1046 setMode(OperatingMode::SYNCING);
1047 else if (mMode == OperatingMode::CONNECTED)
1048 setMode(OperatingMode::CONNECTED);
1051 mConsensus.timerEntry(app_.timeKeeper().closeTime());
1054 if (mLastConsensusPhase != currPhase)
1056 reportConsensusStateChange(currPhase);
1057 mLastConsensusPhase = currPhase;
1060 setHeartbeatTimer();
1064 NetworkOPsImp::processClusterTimer()
1066 if (app_.cluster().size() == 0)
1069 using namespace std::chrono_literals;
1071 bool const update = app_.cluster().update(
1072 app_.nodeIdentity().first,
1074 (m_ledgerMaster.getValidatedLedgerAge() <= 4
min)
1075 ? app_.getFeeTrack().getLocalFee()
1077 app_.timeKeeper().now());
1081 JLOG(m_journal.debug()) <<
"Too soon to send cluster update";
1086 protocol::TMCluster cluster;
1087 app_.cluster().for_each([&cluster](
ClusterNode const& node) {
1088 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1093 n.set_nodename(node.
name());
1097 for (
auto& item : gossip.
items)
1099 protocol::TMLoadSource& node = *cluster.add_loadsources();
1101 node.set_cost(item.balance);
1103 app_.overlay().foreach(
send_if(
1104 std::make_shared<Message>(cluster, protocol::mtCLUSTER),
1115 if (mode == OperatingMode::FULL && admin)
1117 auto const consensusMode = mConsensus.mode();
1118 if (consensusMode != ConsensusMode::wrongLedger)
1120 if (consensusMode == ConsensusMode::proposing)
1123 if (mConsensus.validating())
1124 return "validating";
1134 if (isNeedNetworkLedger())
1143 auto const txid = trans->getTransactionID();
1144 auto const flags = app_.getHashRouter().getFlags(txid);
1146 if ((flags & SF_BAD) != 0)
1148 JLOG(m_journal.warn()) <<
"Submitted transaction cached bad";
1155 app_.getHashRouter(),
1157 m_ledgerMaster.getValidatedRules(),
1160 if (validity != Validity::Valid)
1162 JLOG(m_journal.warn())
1163 <<
"Submitted transaction invalid: " << reason;
1169 JLOG(m_journal.warn())
1170 <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1177 auto tx = std::make_shared<Transaction>(trans, reason, app_);
1179 m_job_queue.addJob(
jtTRANSACTION,
"submitTxn", [
this, tx]() {
1181 processTransaction(t,
false,
false, FailHard::no);
1186 NetworkOPsImp::processTransaction(
1192 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXN");
1193 auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
1195 if ((newFlags & SF_BAD) != 0)
1198 JLOG(m_journal.warn()) << transaction->getID() <<
": cached bad!\n";
1199 transaction->setStatus(
INVALID);
1207 auto const view = m_ledgerMaster.getCurrentLedger();
1209 app_.getHashRouter(),
1210 *transaction->getSTransaction(),
1213 assert(validity == Validity::Valid);
1216 if (validity == Validity::SigBad)
1218 JLOG(m_journal.info()) <<
"Transaction has bad signature: " << reason;
1219 transaction->setStatus(
INVALID);
1221 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
1226 app_.getMasterTransaction().canonicalize(&transaction);
1229 doTransactionSync(transaction, bUnlimited, failType);
1231 doTransactionAsync(transaction, bUnlimited, failType);
1235 NetworkOPsImp::doTransactionAsync(
1242 if (transaction->getApplying())
1245 mTransactions.push_back(
1247 transaction->setApplying();
1249 if (mDispatchState == DispatchState::none)
1251 if (m_job_queue.addJob(
1252 jtBATCH,
"transactionBatch", [
this]() { transactionBatch(); }))
1254 mDispatchState = DispatchState::scheduled;
1260 NetworkOPsImp::doTransactionSync(
1267 if (!transaction->getApplying())
1269 mTransactions.push_back(
1271 transaction->setApplying();
1276 if (mDispatchState == DispatchState::running)
1285 if (mTransactions.size())
1288 if (m_job_queue.addJob(
jtBATCH,
"transactionBatch", [
this]() {
1292 mDispatchState = DispatchState::scheduled;
1296 }
while (transaction->getApplying());
1300 NetworkOPsImp::transactionBatch()
1304 if (mDispatchState == DispatchState::running)
1307 while (mTransactions.size())
1318 mTransactions.
swap(transactions);
1319 assert(!transactions.
empty());
1321 assert(mDispatchState != DispatchState::running);
1322 mDispatchState = DispatchState::running;
1328 bool changed =
false;
1331 m_ledgerMaster.peekMutex(), std::defer_lock};
1342 if (e.failType == FailHard::yes)
1345 auto const result = app_.getTxQ().apply(
1346 app_, view, e.transaction->getSTransaction(), flags, j);
1347 e.result = result.first;
1348 e.applied = result.second;
1349 changed = changed || result.second;
1358 if (
auto const l = m_ledgerMaster.getValidatedLedger())
1359 validatedLedgerIndex = l->info().seq;
1361 auto newOL = app_.openLedger().current();
1364 e.transaction->clearSubmitResult();
1368 pubProposedTransaction(
1369 newOL, e.transaction->getSTransaction(), e.result);
1370 e.transaction->setApplied();
1373 e.transaction->setResult(e.result);
1376 app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
1385 JLOG(m_journal.info())
1386 <<
"TransactionResult: " << token <<
": " << human;
1391 bool addLocal = e.local;
1395 JLOG(m_journal.debug())
1396 <<
"Transaction is now included in open ledger";
1397 e.transaction->setStatus(
INCLUDED);
1399 auto const& txCur = e.transaction->getSTransaction();
1400 auto const txNext = m_ledgerMaster.popAcctTransaction(txCur);
1405 auto t = std::make_shared<Transaction>(trans, reason, app_);
1406 submit_held.
emplace_back(t,
false,
false, FailHard::no);
1413 JLOG(m_journal.info()) <<
"Transaction is obsolete";
1414 e.transaction->setStatus(
OBSOLETE);
1418 JLOG(m_journal.debug())
1419 <<
"Transaction is likely to claim a"
1420 <<
" fee, but is queued until fee drops";
1422 e.transaction->setStatus(
HELD);
1426 m_ledgerMaster.addHeldTransaction(e.transaction);
1427 e.transaction->setQueued();
1428 e.transaction->setKept();
1432 if (e.failType != FailHard::yes)
1435 JLOG(m_journal.debug())
1436 <<
"Transaction should be held: " << e.result;
1437 e.transaction->setStatus(
HELD);
1438 m_ledgerMaster.addHeldTransaction(e.transaction);
1439 e.transaction->setKept();
1444 JLOG(m_journal.debug())
1445 <<
"Status other than success " << e.result;
1446 e.transaction->setStatus(
INVALID);
1449 auto const enforceFailHard =
1450 e.failType == FailHard::yes && !
isTesSuccess(e.result);
1452 if (addLocal && !enforceFailHard)
1454 m_localTX->push_back(
1455 m_ledgerMaster.getCurrentLedgerIndex(),
1456 e.transaction->getSTransaction());
1457 e.transaction->setKept();
1461 ((mMode != OperatingMode::FULL) &&
1462 (e.failType != FailHard::yes) && e.local) ||
1467 app_.getHashRouter().shouldRelay(e.transaction->getID());
1471 protocol::TMTransaction tx;
1474 e.transaction->getSTransaction()->add(s);
1475 tx.set_rawtransaction(s.
data(), s.
size());
1476 tx.set_status(protocol::tsCURRENT);
1477 tx.set_receivetimestamp(
1478 app_.timeKeeper().now().time_since_epoch().count());
1481 app_.overlay().relay(e.transaction->getID(), tx, *toSkip);
1482 e.transaction->setBroadcast();
1486 if (validatedLedgerIndex)
1488 auto [fee, accountSeq, availableSeq] =
1489 app_.getTxQ().getTxRequiredFeeAndSeq(
1490 *newOL, e.transaction->getSTransaction());
1491 e.transaction->setCurrentLedgerState(
1492 *validatedLedgerIndex, fee, accountSeq, availableSeq);
1500 e.transaction->clearApplying();
1502 if (!submit_held.
empty())
1504 if (mTransactions.empty())
1505 mTransactions.swap(submit_held);
1507 for (
auto& e : submit_held)
1508 mTransactions.push_back(std::move(e));
1513 mDispatchState = DispatchState::none;
1521 NetworkOPsImp::getOwnerInfo(
1526 auto root = keylet::ownerDir(account);
1527 auto sleNode = lpLedger->read(keylet::page(
root));
1534 for (
auto const& uDirEntry : sleNode->getFieldV256(
sfIndexes))
1536 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
1539 switch (sleCur->getType())
1542 if (!jvObjects.
isMember(jss::offers))
1543 jvObjects[jss::offers] =
1546 jvObjects[jss::offers].
append(
1547 sleCur->getJson(JsonOptions::none));
1551 if (!jvObjects.
isMember(jss::ripple_lines))
1553 jvObjects[jss::ripple_lines] =
1557 jvObjects[jss::ripple_lines].
append(
1558 sleCur->getJson(JsonOptions::none));
1573 sleNode = lpLedger->read(keylet::page(
root, uNodeDir));
1587 NetworkOPsImp::isBlocked()
1589 return isAmendmentBlocked() || isUNLBlocked();
1593 NetworkOPsImp::isAmendmentBlocked()
1595 return amendmentBlocked_;
1599 NetworkOPsImp::setAmendmentBlocked()
1601 amendmentBlocked_ =
true;
1602 setMode(OperatingMode::CONNECTED);
1606 NetworkOPsImp::isAmendmentWarned()
1608 return !amendmentBlocked_ && amendmentWarned_;
1612 NetworkOPsImp::setAmendmentWarned()
1614 amendmentWarned_ =
true;
1618 NetworkOPsImp::clearAmendmentWarned()
1620 amendmentWarned_ =
false;
1624 NetworkOPsImp::isUNLBlocked()
1630 NetworkOPsImp::setUNLBlocked()
1633 setMode(OperatingMode::CONNECTED);
1637 NetworkOPsImp::clearUNLBlocked()
1639 unlBlocked_ =
false;
1643 NetworkOPsImp::checkLastClosedLedger(
1652 JLOG(m_journal.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
1654 auto const ourClosed = m_ledgerMaster.getClosedLedger();
1659 uint256 closedLedger = ourClosed->info().hash;
1660 uint256 prevClosedLedger = ourClosed->info().parentHash;
1661 JLOG(m_journal.trace()) <<
"OurClosed: " << closedLedger;
1662 JLOG(m_journal.trace()) <<
"PrevClosed: " << prevClosedLedger;
1667 auto& validations = app_.getValidations();
1668 JLOG(m_journal.debug())
1669 <<
"ValidationTrie " <<
Json::Compact(validations.getJsonTrie());
1673 peerCounts[closedLedger] = 0;
1674 if (mMode >= OperatingMode::TRACKING)
1675 peerCounts[closedLedger]++;
1677 for (
auto& peer : peerList)
1679 uint256 peerLedger = peer->getClosedLedgerHash();
1682 ++peerCounts[peerLedger];
1685 for (
auto const& it : peerCounts)
1686 JLOG(m_journal.debug()) <<
"L: " << it.first <<
" n=" << it.second;
1688 uint256 preferredLCL = validations.getPreferredLCL(
1690 m_ledgerMaster.getValidLedgerIndex(),
1693 bool switchLedgers = preferredLCL != closedLedger;
1695 closedLedger = preferredLCL;
1697 if (switchLedgers && (closedLedger == prevClosedLedger))
1700 JLOG(m_journal.info()) <<
"We won't switch to our own previous ledger";
1701 networkClosed = ourClosed->info().hash;
1702 switchLedgers =
false;
1705 networkClosed = closedLedger;
1710 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
1713 consensus = app_.getInboundLedgers().acquire(
1714 closedLedger, 0, InboundLedger::Reason::CONSENSUS);
1717 (!m_ledgerMaster.canBeCurrent(consensus) ||
1718 !m_ledgerMaster.isCompatible(
1719 *consensus, m_journal.debug(),
"Not switching")))
1723 networkClosed = ourClosed->info().hash;
1727 JLOG(m_journal.warn()) <<
"We are not running on the consensus ledger";
1728 JLOG(m_journal.info()) <<
"Our LCL: " <<
getJson({*ourClosed, {}});
1729 JLOG(m_journal.info()) <<
"Net LCL " << closedLedger;
1731 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
1733 setMode(OperatingMode::CONNECTED);
1741 switchLastClosedLedger(consensus);
1748 NetworkOPsImp::switchLastClosedLedger(
1752 JLOG(m_journal.error())
1753 <<
"JUMP last closed ledger to " << newLCL->info().hash;
1755 clearNeedNetworkLedger();
1758 app_.getTxQ().processClosedLedger(app_, *newLCL,
true);
1765 auto retries = m_localTX->getTxSet();
1766 auto const lastVal = app_.getLedgerMaster().getValidatedLedger();
1771 rules.
emplace(app_.config().features);
1772 app_.openLedger().accept(
1783 return app_.getTxQ().accept(app_, view);
1787 m_ledgerMaster.switchLCL(newLCL);
1789 protocol::TMStatusChange s;
1790 s.set_newevent(protocol::neSWITCHED_LEDGER);
1791 s.set_ledgerseq(newLCL->info().seq);
1792 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
1793 s.set_ledgerhashprevious(
1794 newLCL->info().parentHash.begin(), newLCL->info().parentHash.size());
1795 s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size());
1797 app_.overlay().foreach(
1798 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
1802 NetworkOPsImp::beginConsensus(
uint256 const& networkClosed)
1806 auto closingInfo = m_ledgerMaster.getCurrentLedger()->info();
1808 JLOG(m_journal.info()) <<
"Consensus time for #" << closingInfo.seq
1809 <<
" with LCL " << closingInfo.parentHash;
1811 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
1816 if (mMode == OperatingMode::FULL)
1818 JLOG(m_journal.warn()) <<
"Don't have LCL, going to tracking";
1819 setMode(OperatingMode::TRACKING);
1825 assert(prevLedger->info().hash == closingInfo.parentHash);
1827 closingInfo.parentHash ==
1828 m_ledgerMaster.getClosedLedger()->info().hash);
1831 app_.validators().setNegativeUNL(prevLedger->negativeUNL());
1832 TrustChanges const changes = app_.validators().updateTrusted(
1833 app_.getValidations().getCurrentNodeIDs(),
1834 closingInfo.parentCloseTime,
1837 app_.getHashRouter());
1839 if (!changes.
added.empty() || !changes.
removed.empty())
1840 app_.getValidations().trustChanged(changes.
added, changes.
removed);
1842 mConsensus.startRound(
1843 app_.timeKeeper().closeTime(),
1850 if (mLastConsensusPhase != currPhase)
1852 reportConsensusStateChange(currPhase);
1853 mLastConsensusPhase = currPhase;
1856 JLOG(m_journal.debug()) <<
"Initiating consensus engine";
1863 return mConsensus.peerProposal(app_.timeKeeper().closeTime(), peerPos);
1874 protocol::TMHaveTransactionSet msg;
1875 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
1876 msg.set_status(protocol::tsHAVE);
1877 app_.overlay().foreach(
1878 send_always(std::make_shared<Message>(msg, protocol::mtHAVE_SET)));
1882 mConsensus.gotTxSet(app_.timeKeeper().closeTime(),
RCLTxSet{map});
1886 NetworkOPsImp::endConsensus()
1888 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash;
1890 for (
auto const& it : app_.overlay().getActivePeers())
1892 if (it && (it->getClosedLedgerHash() == deadLedger))
1894 JLOG(m_journal.trace()) <<
"Killing obsolete peer status";
1901 checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed);
1903 if (networkClosed.
isZero())
1912 if (((mMode == OperatingMode::CONNECTED) ||
1913 (mMode == OperatingMode::SYNCING)) &&
1919 if (!needNetworkLedger_)
1920 setMode(OperatingMode::TRACKING);
1923 if (((mMode == OperatingMode::CONNECTED) ||
1924 (mMode == OperatingMode::TRACKING)) &&
1930 auto current = m_ledgerMaster.getCurrentLedger();
1931 if (app_.timeKeeper().now() < (
current->info().parentCloseTime +
1932 2 *
current->info().closeTimeResolution))
1934 setMode(OperatingMode::FULL);
1938 beginConsensus(networkClosed);
1942 NetworkOPsImp::consensusViewChange()
1944 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
1946 setMode(OperatingMode::CONNECTED);
1956 if (!mStreamMaps[sManifests].empty())
1960 jvObj[jss::type] =
"manifestReceived";
1963 jvObj[jss::signing_key] =
1967 jvObj[jss::signature] =
strHex(*sig);
1970 jvObj[jss::domain] = mo.
domain;
1973 for (
auto i = mStreamMaps[sManifests].begin();
1974 i != mStreamMaps[sManifests].end();)
1976 if (
auto p = i->second.lock())
1978 p->send(jvObj,
true);
1983 i = mStreamMaps[sManifests].erase(i);
1989 NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
1994 , loadBaseServer{loadFeeTrack.getLoadBase()}
1996 , em{std::move(escalationMetrics)}
2006 em.has_value() != b.
em.has_value())
2012 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2013 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2014 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2047 jvObj[jss::type] =
"serverStatus";
2049 jvObj[jss::load_base] = f.loadBaseServer;
2050 jvObj[jss::load_factor_server] = f.loadFactorServer;
2051 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
2056 safe_cast<std::uint64_t>(f.loadFactorServer),
2058 f.em->openLedgerFeeLevel,
2060 f.em->referenceFeeLevel)
2063 jvObj[jss::load_factor] =
trunc32(loadFactor);
2064 jvObj[jss::load_factor_fee_escalation] =
2065 f.em->openLedgerFeeLevel.jsonClipped();
2066 jvObj[jss::load_factor_fee_queue] =
2067 f.em->minProcessingFeeLevel.jsonClipped();
2068 jvObj[jss::load_factor_fee_reference] =
2069 f.em->referenceFeeLevel.jsonClipped();
2072 jvObj[jss::load_factor] = f.loadFactorServer;
2086 p->send(jvObj,
true);
2103 if (!streamMap.empty())
2106 jvObj[jss::type] =
"consensusPhase";
2107 jvObj[jss::consensus] =
to_string(phase);
2109 for (
auto i = streamMap.begin(); i != streamMap.end();)
2111 if (
auto p = i->second.lock())
2113 p->send(jvObj,
true);
2118 i = streamMap.erase(i);
2134 auto const signerPublic = val->getSignerPublic();
2136 jvObj[jss::type] =
"validationReceived";
2137 jvObj[jss::validation_public_key] =
2139 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2140 jvObj[jss::signature] =
strHex(val->getSignature());
2141 jvObj[jss::full] = val->isFull();
2142 jvObj[jss::flags] = val->getFlags();
2144 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2149 if (
auto cookie = (*val)[~
sfCookie])
2153 jvObj[jss::validated_hash] =
strHex(*hash);
2155 auto const masterKey =
2158 if (masterKey != signerPublic)
2162 jvObj[jss::ledger_index] =
to_string(*seq);
2167 for (
auto const& amendment : val->getFieldV256(
sfAmendments))
2172 jvObj[jss::close_time] = *closeTime;
2174 if (
auto const loadFee = (*val)[~
sfLoadFee])
2175 jvObj[jss::load_fee] = *loadFee;
2177 if (
auto const baseFee = val->at(~
sfBaseFee))
2178 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2181 jvObj[jss::reserve_base] = *reserveBase;
2184 jvObj[jss::reserve_inc] = *reserveInc;
2189 baseFeeXRP && baseFeeXRP->native())
2190 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2193 reserveBaseXRP && reserveBaseXRP->native())
2194 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2197 reserveIncXRP && reserveIncXRP->native())
2198 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2203 if (
auto p = i->second.lock())
2205 p->send(jvObj,
true);
2225 jvObj[jss::type] =
"peerStatusChange";
2234 p->send(jvObj,
true);
2248 using namespace std::chrono_literals;
2280 <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2310 "This server is amendment blocked, and must be updated to be "
2311 "able to stay in sync with the network.";
2318 "This server has an expired validator list. validators.txt "
2319 "may be incorrectly configured or some [validator_list_sites] "
2320 "may be unreachable.";
2327 "One or more unsupported amendments have reached majority. "
2328 "Upgrade to the latest version before they are activated "
2329 "to avoid being amendment blocked.";
2330 if (
auto const expected =
2334 d[jss::expected_date] = expected->time_since_epoch().count();
2335 d[jss::expected_date_UTC] =
to_string(*expected);
2339 if (warnings.size())
2340 info[jss::warnings] = std::move(warnings);
2355 info[jss::time] =
to_string(std::chrono::floor<std::chrono::microseconds>(
2359 info[jss::network_ledger] =
"waiting";
2361 info[jss::validation_quorum] =
2369 info[jss::node_size] =
"tiny";
2372 info[jss::node_size] =
"small";
2375 info[jss::node_size] =
"medium";
2378 info[jss::node_size] =
"large";
2381 info[jss::node_size] =
"huge";
2390 info[jss::validator_list_expires] =
2391 safe_cast<Json::UInt>(when->time_since_epoch().count());
2393 info[jss::validator_list_expires] = 0;
2403 if (*when == TimeKeeper::time_point::max())
2405 x[jss::expiration] =
"never";
2406 x[jss::status] =
"active";
2413 x[jss::status] =
"active";
2415 x[jss::status] =
"expired";
2420 x[jss::status] =
"unknown";
2421 x[jss::expiration] =
"unknown";
2425 info[jss::io_latency_ms] =
2432 info[jss::pubkey_validator] =
toBase58(
2437 info[jss::pubkey_validator] =
"none";
2450 info[jss::counters][jss::nodestore] = nodestore;
2454 info[jss::pubkey_node] =
2460 info[jss::amendment_blocked] =
true;
2475 lastClose[jss::converge_time_s] =
2480 lastClose[jss::converge_time] =
2484 info[jss::last_close] = lastClose;
2494 info[jss::network_id] =
static_cast<Json::UInt>(*netid);
2496 auto const escalationMetrics =
2504 auto const loadFactorFeeEscalation =
2506 escalationMetrics.openLedgerFeeLevel,
2508 escalationMetrics.referenceFeeLevel)
2512 safe_cast<std::uint64_t>(loadFactorServer),
2513 loadFactorFeeEscalation);
2517 info[jss::load_base] = loadBaseServer;
2518 info[jss::load_factor] =
trunc32(loadFactor);
2519 info[jss::load_factor_server] = loadFactorServer;
2526 info[jss::load_factor_fee_escalation] =
2527 escalationMetrics.openLedgerFeeLevel.jsonClipped();
2528 info[jss::load_factor_fee_queue] =
2529 escalationMetrics.minProcessingFeeLevel.jsonClipped();
2530 info[jss::load_factor_fee_reference] =
2531 escalationMetrics.referenceFeeLevel.jsonClipped();
2535 info[jss::load_factor] =
2536 static_cast<double>(loadFactor) / loadBaseServer;
2538 if (loadFactorServer != loadFactor)
2539 info[jss::load_factor_server] =
2540 static_cast<double>(loadFactorServer) / loadBaseServer;
2545 if (fee != loadBaseServer)
2546 info[jss::load_factor_local] =
2547 static_cast<double>(fee) / loadBaseServer;
2549 if (fee != loadBaseServer)
2550 info[jss::load_factor_net] =
2551 static_cast<double>(fee) / loadBaseServer;
2553 if (fee != loadBaseServer)
2554 info[jss::load_factor_cluster] =
2555 static_cast<double>(fee) / loadBaseServer;
2557 if (escalationMetrics.openLedgerFeeLevel !=
2558 escalationMetrics.referenceFeeLevel &&
2559 (admin || loadFactorFeeEscalation != loadFactor))
2560 info[jss::load_factor_fee_escalation] =
2561 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
2562 escalationMetrics.referenceFeeLevel);
2563 if (escalationMetrics.minProcessingFeeLevel !=
2564 escalationMetrics.referenceFeeLevel)
2565 info[jss::load_factor_fee_queue] =
2566 escalationMetrics.minProcessingFeeLevel
2567 .decimalFromReference(
2568 escalationMetrics.referenceFeeLevel);
2582 XRPAmount const baseFee = lpClosed->fees().base;
2584 l[jss::seq] =
Json::UInt(lpClosed->info().seq);
2585 l[jss::hash] =
to_string(lpClosed->info().hash);
2590 l[jss::reserve_base] =
2591 lpClosed->fees().accountReserve(0).jsonClipped();
2592 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
2594 lpClosed->info().closeTime.time_since_epoch().count());
2599 l[jss::reserve_base_xrp] =
2600 lpClosed->fees().accountReserve(0).decimalXRP();
2601 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
2604 if (std::abs(nowOffset.count()) >= 60)
2605 l[jss::system_time_offset] = nowOffset.count();
2608 if (std::abs(closeOffset.count()) >= 60)
2609 l[jss::close_time_offset] = closeOffset.count();
2611 #if RIPPLED_REPORTING
2621 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2625 auto lCloseTime = lpClosed->info().closeTime;
2627 if (lCloseTime <= closeTime)
2629 using namespace std::chrono_literals;
2630 auto age = closeTime - lCloseTime;
2632 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2639 info[jss::validated_ledger] = l;
2641 info[jss::closed_ledger] = l;
2645 info[jss::published_ledger] =
"none";
2646 else if (lpPublished->info().seq != lpClosed->info().seq)
2647 info[jss::published_ledger] = lpPublished->info().seq;
2654 info[jss::jq_trans_overflow] =
2656 info[jss::peer_disconnects] =
2658 info[jss::peer_disconnects_resources] =
2668 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
2676 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
2677 port.admin_user.empty() && port.admin_password.empty()))
2691 for (
auto const& p : proto)
2692 jv[jss::protocol].append(p);
2699 auto const optPort = grpcSection.
get(
"port");
2700 if (optPort && grpcSection.get(
"ip"))
2703 jv[jss::port] = *optPort;
2705 jv[jss::protocol].append(
"grpc");
2708 info[jss::ports] = std::move(ports);
2744 p->send(jvObj,
true);
2763 if (jvObj[jss::validated].asBool())
2775 p->send(jvObj,
true);
2796 if (
auto p = i->second.lock())
2798 p->send(jvObj,
true);
2816 if (
auto p = i->second.lock())
2818 p->send(jvObj,
true);
2831 for (
auto& jv : jvObj)
2837 else if (jv.isString())
2861 if (jvObj.
isMember(jss::transaction))
2870 << __func__ <<
" : "
2871 <<
"error parsing json for accounts affected";
2880 for (
auto const& affectedAccount : accounts)
2885 auto it = simiIt->second.begin();
2887 while (it != simiIt->second.end())
2898 it = simiIt->second.erase(it);
2905 <<
" iProposed=" << iProposed;
2907 if (!notify.
empty())
2910 isrListener->send(jvObj,
true);
2924 alpAccepted = std::make_shared<AcceptedLedger>(lpAccepted,
app_);
2926 lpAccepted->info().hash, alpAccepted);
2929 assert(alpAccepted->getLedger().
get() == lpAccepted.
get());
2933 <<
"Publishing ledger " << lpAccepted->info().seq <<
" "
2934 << lpAccepted->info().hash;
2942 jvObj[jss::type] =
"ledgerClosed";
2943 jvObj[jss::ledger_index] = lpAccepted->info().seq;
2944 jvObj[jss::ledger_hash] =
to_string(lpAccepted->info().hash);
2946 lpAccepted->info().closeTime.time_since_epoch().count());
2950 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
2951 jvObj[jss::reserve_base] =
2952 lpAccepted->fees().accountReserve(0).jsonClipped();
2953 jvObj[jss::reserve_inc] =
2954 lpAccepted->fees().increment.jsonClipped();
2956 jvObj[jss::txn_count] =
Json::UInt(alpAccepted->size());
2960 jvObj[jss::validated_ledgers] =
2970 p->send(jvObj,
true);
2988 p->send(jvObj,
true);
2997 static bool firstTime =
true;
3004 for (
auto& inner : outer.second)
3006 auto& subInfo = inner.second;
3007 if (subInfo.index_->separationLedgerSeq_ == 0)
3010 alpAccepted->getLedger(), subInfo);
3019 for (
auto const& accTx : *alpAccepted)
3051 "reportConsensusStateChange->pubConsensus",
3070 const STTx& transaction,
3081 jvObj[jss::type] =
"transaction";
3086 jvObj[jss::ledger_index] = ledger->info().seq;
3087 jvObj[jss::ledger_hash] =
to_string(ledger->info().hash);
3088 jvObj[jss::transaction][jss::date] =
3089 ledger->info().closeTime.time_since_epoch().count();
3090 jvObj[jss::validated] =
true;
3096 jvObj[jss::validated] =
false;
3097 jvObj[jss::ledger_current_index] = ledger->info().seq;
3100 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3101 jvObj[jss::engine_result] = sToken;
3102 jvObj[jss::engine_result_code] = result;
3103 jvObj[jss::engine_result_message] = sHuman;
3111 if (account != amount.issue().account)
3119 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3131 auto const& stTxn = transaction.
getTxn();
3137 auto const& meta = transaction.
getMeta();
3152 p->send(jvObj,
true);
3167 p->send(jvObj,
true);
3191 auto const currLedgerSeq = ledger->seq();
3198 for (
auto const& affectedAccount : transaction.
getAffected())
3203 auto it = simiIt->second.begin();
3205 while (it != simiIt->second.end())
3216 it = simiIt->second.erase(it);
3223 auto it = simiIt->second.begin();
3224 while (it != simiIt->second.end())
3235 it = simiIt->second.erase(it);
3242 auto& subs = histoIt->second;
3243 auto it = subs.begin();
3244 while (it != subs.end())
3247 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
3261 it = subs.erase(it);
3272 <<
"pubAccountTransaction: "
3273 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3275 if (!notify.
empty() || !accountHistoryNotify.
empty())
3277 auto const& stTxn = transaction.
getTxn();
3283 auto const& meta = transaction.
getMeta();
3290 isrListener->send(jvObj,
true);
3292 assert(!jvObj.
isMember(jss::account_history_tx_stream));
3293 for (
auto& info : accountHistoryNotify)
3295 auto& index = info.index_;
3296 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3297 jvObj[jss::account_history_tx_first] =
true;
3298 jvObj[jss::account_history_tx_index] = index->forwardTxIndex_++;
3299 info.sink_->send(jvObj,
true);
3324 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3329 auto it = simiIt->second.begin();
3331 while (it != simiIt->second.end())
3342 it = simiIt->second.erase(it);
3349 JLOG(
m_journal.
trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3351 if (!notify.
empty() || !accountHistoryNotify.
empty())
3356 isrListener->send(jvObj,
true);
3358 assert(!jvObj.
isMember(jss::account_history_tx_stream));
3359 for (
auto& info : accountHistoryNotify)
3361 auto& index = info.index_;
3362 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3363 jvObj[jss::account_history_tx_first] =
true;
3364 jvObj[jss::account_history_tx_index] = index->forwardTxIndex_++;
3365 info.sink_->send(jvObj,
true);
3382 for (
auto const& naAccountID : vnaAccountIDs)
3385 <<
"subAccount: account: " <<
toBase58(naAccountID);
3387 isrListener->insertSubAccountInfo(naAccountID, rt);
3392 for (
auto const& naAccountID : vnaAccountIDs)
3394 auto simIterator = subMap.
find(naAccountID);
3395 if (simIterator == subMap.
end())
3399 usisElement[isrListener->getSeq()] = isrListener;
3401 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3406 simIterator->second[isrListener->getSeq()] = isrListener;
3417 for (
auto const& naAccountID : vnaAccountIDs)
3420 isrListener->deleteSubAccountInfo(naAccountID, rt);
3437 for (
auto const& naAccountID : vnaAccountIDs)
3439 auto simIterator = subMap.
find(naAccountID);
3441 if (simIterator != subMap.
end())
3444 simIterator->second.erase(uSeq);
3446 if (simIterator->second.empty())
3449 subMap.
erase(simIterator);
3458 enum DatabaseType { Postgres, Sqlite, None };
3459 static const auto databaseType = [&]() -> DatabaseType {
3460 #ifdef RIPPLED_REPORTING
3467 return DatabaseType::Postgres;
3469 return DatabaseType::None;
3477 return DatabaseType::Sqlite;
3479 return DatabaseType::None;
3486 return DatabaseType::Sqlite;
3488 return DatabaseType::None;
3492 if (databaseType == DatabaseType::None)
3495 <<
"AccountHistory job for account "
3507 "AccountHistoryTxStream",
3508 [
this, dbType = databaseType, subInfo]() {
3509 auto const& accountId = subInfo.
index_->accountId_;
3510 auto& lastLedgerSeq = subInfo.
index_->historyLastLedgerSeq_;
3511 auto& txHistoryIndex = subInfo.
index_->historyTxIndex_;
3514 <<
"AccountHistory job for account " <<
toBase58(accountId)
3515 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
3525 auto stx = tx->getSTransaction();
3526 if (stx->getAccountID(
sfAccount) == accountId &&
3527 stx->getSeqProxy().value() == 1)
3531 for (
auto& node : meta->getNodes())
3538 if (
auto inner =
dynamic_cast<const STObject*
>(
3543 inner->getAccountID(
sfAccount) == accountId)
3555 bool unsubscribe) ->
bool {
3558 sptr->send(jvObj,
true);
3584 auto [txResult, status] = db->getAccountTx(args);
3588 <<
"AccountHistory job for account "
3590 <<
" getAccountTx failed";
3595 std::get_if<RelationalDatabase::AccountTxs>(
3596 &txResult.transactions);
3604 <<
"AccountHistory job for account "
3606 <<
" getAccountTx wrong data";
3614 accountId, minLedger, maxLedger, marker, 0,
true};
3615 return db->newestAccountTxPage(options);
3627 while (lastLedgerSeq >= 2 && !subInfo.
index_->stopHistorical_)
3629 int feeChargeCount = 0;
3638 <<
"AccountHistory job for account "
3639 <<
toBase58(accountId) <<
" no InfoSub. Fee charged "
3640 << feeChargeCount <<
" times.";
3645 auto startLedgerSeq =
3646 (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
3648 <<
"AccountHistory job for account " <<
toBase58(accountId)
3649 <<
", working on ledger range [" << startLedgerSeq <<
","
3650 << lastLedgerSeq <<
"]";
3652 auto haveRange = [&]() ->
bool {
3655 auto haveSomeValidatedLedgers =
3657 validatedMin, validatedMax);
3659 return haveSomeValidatedLedgers &&
3660 validatedMin <= startLedgerSeq &&
3661 lastLedgerSeq <= validatedMax;
3667 <<
"AccountHistory reschedule job for account "
3668 <<
toBase58(accountId) <<
", incomplete ledger range ["
3669 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3675 while (!subInfo.
index_->stopHistorical_)
3678 getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
3682 <<
"AccountHistory job for account "
3683 <<
toBase58(accountId) <<
" getMoreTxns failed.";
3688 auto const& txns = dbResult->first;
3689 marker = dbResult->second;
3690 for (
auto const& [tx, meta] : txns)
3695 <<
"AccountHistory job for account "
3696 <<
toBase58(accountId) <<
" empty tx or meta.";
3706 <<
"AccountHistory job for account "
3707 <<
toBase58(accountId) <<
" no ledger.";
3712 tx->getSTransaction();
3716 <<
"AccountHistory job for account "
3718 <<
" getSTransaction failed.";
3723 *stTxn, meta->getResultTER(),
true, curTxLedger);
3725 jvTx[jss::account_history_tx_index] = txHistoryIndex--;
3727 jvTx[jss::meta], *curTxLedger, stTxn, *meta);
3728 if (isFirstTx(tx, meta))
3730 jvTx[jss::account_history_tx_first] =
true;
3734 <<
"AccountHistory job for account "
3736 <<
" done, found last tx.";
3748 <<
"AccountHistory job for account "
3750 <<
" paging, marker=" << marker->ledgerSeq <<
":"
3759 if (!subInfo.
index_->stopHistorical_)
3761 lastLedgerSeq = startLedgerSeq - 1;
3762 if (lastLedgerSeq <= 1)
3765 <<
"AccountHistory job for account "
3767 <<
" done, reached genesis ledger.";
3780 subInfo.
index_->separationLedgerSeq_ = ledger->seq();
3781 auto const& accountId = subInfo.
index_->accountId_;
3783 if (!ledger->exists(accountKeylet))
3786 <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
3787 <<
", no need to add AccountHistory job.";
3792 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
3797 <<
"subAccountHistoryStart, genesis account "
3799 <<
" does not have tx, no need to add AccountHistory job.";
3809 subInfo.
index_->historyLastLedgerSeq_ = ledger->seq();
3810 subInfo.
index_->haveHistorical_ =
true;
3813 <<
"subAccountHistoryStart, add AccountHistory job: accountId="
3814 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
3824 if (!isrListener->insertSubAccountHistory(accountId))
3827 <<
"subAccountHistory, already subscribed to account "
3834 isrListener, std::make_shared<SubAccountHistoryIndex>(accountId)};
3839 inner.
emplace(isrListener->getSeq(), ahi);
3845 simIterator->second.emplace(isrListener->getSeq(), ahi);
3859 <<
"subAccountHistory, no validated ledger yet, delay start";
3872 isrListener->deleteSubAccountHistory(account);
3886 auto& subInfoMap = simIterator->second;
3887 auto subInfoIter = subInfoMap.find(seq);
3888 if (subInfoIter != subInfoMap.end())
3890 subInfoIter->second.index_->stopHistorical_ =
true;
3895 simIterator->second.erase(seq);
3896 if (simIterator->second.empty())
3902 <<
"unsubAccountHistory, account " <<
toBase58(account)
3903 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
3911 listeners->addSubscriber(isrListener);
3921 listeners->removeSubscriber(uSeq);
3935 Throw<std::runtime_error>(
3936 "Operation only possible in STANDALONE mode.");
3951 jvResult[jss::ledger_index] = lpClosed->info().seq;
3952 jvResult[jss::ledger_hash] =
to_string(lpClosed->info().hash);
3954 lpClosed->info().closeTime.time_since_epoch().count());
3957 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
3958 jvResult[jss::reserve_base] =
3959 lpClosed->fees().accountReserve(0).jsonClipped();
3960 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
3965 jvResult[jss::validated_ledgers] =
3971 .emplace(isrListener->getSeq(), isrListener)
3981 .emplace(isrListener->getSeq(), isrListener)
4007 .emplace(isrListener->getSeq(), isrListener)
4035 jvResult[jss::random] =
to_string(uRandom);
4037 jvResult[jss::load_base] = feeTrack.getLoadBase();
4038 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4039 jvResult[jss::hostid] =
getHostId(admin);
4040 jvResult[jss::pubkey_node] =
4045 .emplace(isrListener->getSeq(), isrListener)
4063 .emplace(isrListener->getSeq(), isrListener)
4081 .emplace(isrListener->getSeq(), isrListener)
4099 .emplace(isrListener->getSeq(), isrListener)
4123 .emplace(isrListener->getSeq(), isrListener)
4141 .emplace(isrListener->getSeq(), isrListener)
4189 if (map.find(pInfo->getSeq()) != map.end())
4196 #ifndef USE_NEW_BOOK_PAGE
4207 unsigned int iLimit,
4217 uint256 uTipIndex = uBookBase;
4221 stream <<
"getBookPage:" << book;
4222 stream <<
"getBookPage: uBookBase=" << uBookBase;
4223 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4224 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4233 bool bDirectAdvance =
true;
4237 unsigned int uBookEntry;
4243 while (!bDone && iLimit-- > 0)
4247 bDirectAdvance =
false;
4251 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4255 sleOfferDir.
reset();
4264 uTipIndex = sleOfferDir->key();
4267 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4270 <<
"getBookPage: uTipIndex=" << uTipIndex;
4272 <<
"getBookPage: offerIndex=" << offerIndex;
4282 auto const uOfferOwnerID = sleOffer->getAccountID(
sfAccount);
4283 auto const& saTakerGets = sleOffer->getFieldAmount(
sfTakerGets);
4284 auto const& saTakerPays = sleOffer->getFieldAmount(
sfTakerPays);
4286 bool firstOwnerOffer(
true);
4292 saOwnerFunds = saTakerGets;
4294 else if (bGlobalFreeze)
4302 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4303 if (umBalanceEntry != umBalance.
end())
4307 saOwnerFunds = umBalanceEntry->second;
4308 firstOwnerOffer =
false;
4322 if (saOwnerFunds < beast::zero)
4326 saOwnerFunds.
clear();
4334 STAmount saOwnerFundsLimit = saOwnerFunds;
4346 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4349 if (saOwnerFundsLimit >= saTakerGets)
4352 saTakerGetsFunded = saTakerGets;
4358 saTakerGetsFunded = saOwnerFundsLimit;
4360 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4364 saTakerGetsFunded, saDirRate, saTakerPays.
issue()))
4365 .setJson(jvOffer[jss::taker_pays_funded]);
4371 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4373 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4377 jvOf[jss::quality] = saDirRate.
getText();
4379 if (firstOwnerOffer)
4380 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4387 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4389 bDirectAdvance =
true;
4394 <<
"getBookPage: offerIndex=" << offerIndex;
4414 unsigned int iLimit,
4422 MetaView lesActive(lpLedger,
tapNONE,
true);
4423 OrderBookIterator obIterator(lesActive, book);
4427 const bool bGlobalFreeze = lesActive.isGlobalFrozen(book.
out.
account) ||
4428 lesActive.isGlobalFrozen(book.
in.
account);
4430 while (iLimit-- > 0 && obIterator.nextOffer())
4435 auto const uOfferOwnerID = sleOffer->getAccountID(
sfAccount);
4436 auto const& saTakerGets = sleOffer->getFieldAmount(
sfTakerGets);
4437 auto const& saTakerPays = sleOffer->getFieldAmount(
sfTakerPays);
4438 STAmount saDirRate = obIterator.getCurrentRate();
4444 saOwnerFunds = saTakerGets;
4446 else if (bGlobalFreeze)
4454 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4456 if (umBalanceEntry != umBalance.
end())
4460 saOwnerFunds = umBalanceEntry->second;
4466 saOwnerFunds = lesActive.accountHolds(
4472 if (saOwnerFunds.isNegative())
4476 saOwnerFunds.zero();
4483 STAmount saTakerGetsFunded;
4484 STAmount saOwnerFundsLimit = saOwnerFunds;
4496 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4499 if (saOwnerFundsLimit >= saTakerGets)
4502 saTakerGetsFunded = saTakerGets;
4507 saTakerGetsFunded = saOwnerFundsLimit;
4509 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
4515 multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
4516 .setJson(jvOffer[jss::taker_pays_funded]);
4519 STAmount saOwnerPays = (
parityRate == offerRate)
4522 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4524 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4526 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
4530 jvOf[jss::quality] = saDirRate.
getText();
4545 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4585 ++counters_[
static_cast<std::size_t>(om)].transitions;
4587 counters_[
static_cast<std::size_t>(om)].transitions == 1)
4589 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(
4590 now - processStart_)
4594 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
4603 auto [counters, mode, start, initialSync] = getCounterData();
4604 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4614 auto& state = obj[jss::state_accounting][
states_[i]];
4615 state[jss::transitions] =
std::to_string(counters[i].transitions);
4616 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
4620 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
4635 boost::asio::io_service& io_svc,
4639 return std::make_unique<NetworkOPsImp>(