20#include <xrpld/app/consensus/RCLConsensus.h>
21#include <xrpld/app/consensus/RCLValidations.h>
22#include <xrpld/app/ledger/AcceptedLedger.h>
23#include <xrpld/app/ledger/InboundLedgers.h>
24#include <xrpld/app/ledger/LedgerMaster.h>
25#include <xrpld/app/ledger/LedgerToJson.h>
26#include <xrpld/app/ledger/LocalTxs.h>
27#include <xrpld/app/ledger/OpenLedger.h>
28#include <xrpld/app/ledger/OrderBookDB.h>
29#include <xrpld/app/ledger/TransactionMaster.h>
30#include <xrpld/app/main/LoadManager.h>
31#include <xrpld/app/main/Tuning.h>
32#include <xrpld/app/misc/AmendmentTable.h>
33#include <xrpld/app/misc/DeliverMax.h>
34#include <xrpld/app/misc/HashRouter.h>
35#include <xrpld/app/misc/LoadFeeTrack.h>
36#include <xrpld/app/misc/NetworkOPs.h>
37#include <xrpld/app/misc/Transaction.h>
38#include <xrpld/app/misc/TxQ.h>
39#include <xrpld/app/misc/ValidatorKeys.h>
40#include <xrpld/app/misc/ValidatorList.h>
41#include <xrpld/app/misc/detail/AccountTxPaging.h>
42#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
43#include <xrpld/app/tx/apply.h>
44#include <xrpld/consensus/Consensus.h>
45#include <xrpld/consensus/ConsensusParms.h>
46#include <xrpld/overlay/Cluster.h>
47#include <xrpld/overlay/Overlay.h>
48#include <xrpld/overlay/predicates.h>
49#include <xrpld/perflog/PerfLog.h>
50#include <xrpld/rpc/BookChanges.h>
51#include <xrpld/rpc/CTID.h>
52#include <xrpld/rpc/DeliveredAmount.h>
53#include <xrpld/rpc/MPTokenIssuanceID.h>
54#include <xrpld/rpc/ServerHandler.h>
56#include <xrpl/basics/UptimeClock.h>
57#include <xrpl/basics/mulDiv.h>
58#include <xrpl/basics/safe_cast.h>
59#include <xrpl/basics/scope.h>
60#include <xrpl/beast/utility/rngfill.h>
61#include <xrpl/crypto/RFC1751.h>
62#include <xrpl/crypto/csprng.h>
63#include <xrpl/protocol/BuildInfo.h>
64#include <xrpl/protocol/Feature.h>
65#include <xrpl/protocol/MultiApiJson.h>
66#include <xrpl/protocol/RPCErr.h>
67#include <xrpl/protocol/jss.h>
68#include <xrpl/resource/Fees.h>
69#include <xrpl/resource/ResourceManager.h>
71#include <boost/asio/ip/host_name.hpp>
72#include <boost/asio/steady_timer.hpp>
111 "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : "
154 std::chrono::steady_clock::time_point
start_ =
215 return !(*
this != b);
234 boost::asio::io_service& io_svc,
248 app_.logs().journal(
"FeeVote")),
251 app.getInboundTransactions(),
252 beast::get_abstract_clock<
std::chrono::steady_clock>(),
254 app_.logs().journal(
"LedgerConsensus"))
256 validatorKeys.keys ? validatorKeys.keys->publicKey
259 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
454 getServerInfo(
bool human,
bool admin,
bool counters)
override;
481 TER result)
override;
515 bool historyOnly)
override;
521 bool historyOnly)
override;
589 boost::system::error_code ec;
594 <<
"NetworkOPs: heartbeatTimer cancel error: "
603 <<
"NetworkOPs: clusterTimer cancel error: "
612 <<
"NetworkOPs: accountHistoryTxTimer cancel error: "
617 using namespace std::chrono_literals;
627 boost::asio::steady_timer& timer,
810 template <
class Handler>
812 Handler
const& handler,
814 :
hook(collector->make_hook(handler))
817 "Disconnected_duration"))
820 "Connected_duration"))
822 collector->make_gauge(
"State_Accounting",
"Syncing_duration"))
825 "Tracking_duration"))
827 collector->make_gauge(
"State_Accounting",
"Full_duration"))
830 "Disconnected_transitions"))
833 "Connected_transitions"))
836 "Syncing_transitions"))
839 "Tracking_transitions"))
841 collector->make_gauge(
"State_Accounting",
"Full_transitions"))
870 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
932 static std::string const hostname = boost::asio::ip::host_name();
939 static std::string const shroudedHostId = [
this]() {
945 return shroudedHostId;
960 boost::asio::steady_timer& timer,
967 [
this, onExpire, onError](boost::system::error_code
const& e) {
968 if ((e.value() == boost::system::errc::success) &&
969 (!m_job_queue.isStopped()))
974 if (e.value() != boost::system::errc::success &&
975 e.value() != boost::asio::error::operation_aborted)
978 JLOG(m_journal.error())
979 <<
"Timer got error '" << e.message()
980 <<
"'. Restarting timer.";
985 timer.expires_from_now(expiry_time);
986 timer.async_wait(std::move(*optionalCountedHandler));
991NetworkOPsImp::setHeartbeatTimer()
995 mConsensus.parms().ledgerGRANULARITY,
997 m_job_queue.addJob(jtNETOP_TIMER,
"NetOPs.heartbeat", [this]() {
998 processHeartbeatTimer();
1001 [
this]() { setHeartbeatTimer(); });
1005NetworkOPsImp::setClusterTimer()
1007 using namespace std::chrono_literals;
1014 processClusterTimer();
1017 [
this]() { setClusterTimer(); });
1023 JLOG(m_journal.debug()) <<
"Scheduling AccountHistory job for account "
1025 using namespace std::chrono_literals;
1027 accountHistoryTxTimer_,
1029 [
this, subInfo]() { addAccountHistoryJob(subInfo); },
1030 [
this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
1034NetworkOPsImp::processHeartbeatTimer()
1037 "Heartbeat Timer", mConsensus.validating(), m_journal);
1045 std::size_t const numPeers = app_.overlay().size();
1048 if (numPeers < minPeerCount_)
1050 if (mMode != OperatingMode::DISCONNECTED)
1052 setMode(OperatingMode::DISCONNECTED);
1054 ss <<
"Node count (" << numPeers <<
") has fallen "
1055 <<
"below required minimum (" << minPeerCount_ <<
").";
1056 JLOG(m_journal.warn()) << ss.
str();
1057 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
1062 <<
"already DISCONNECTED. too few peers (" << numPeers
1063 <<
"), need at least " << minPeerCount_;
1070 setHeartbeatTimer();
1075 if (mMode == OperatingMode::DISCONNECTED)
1077 setMode(OperatingMode::CONNECTED);
1078 JLOG(m_journal.info())
1079 <<
"Node count (" << numPeers <<
") is sufficient.";
1080 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers
1086 auto origMode = mMode.load();
1087 CLOG(clog.
ss()) <<
"mode: " << strOperatingMode(origMode,
true);
1088 if (mMode == OperatingMode::SYNCING)
1089 setMode(OperatingMode::SYNCING);
1090 else if (mMode == OperatingMode::CONNECTED)
1091 setMode(OperatingMode::CONNECTED);
1092 auto newMode = mMode.load();
1093 if (origMode != newMode)
1096 <<
", changing to " << strOperatingMode(newMode,
true);
1098 CLOG(clog.
ss()) <<
". ";
1101 mConsensus.timerEntry(app_.timeKeeper().closeTime(), clog.
ss());
1103 CLOG(clog.
ss()) <<
"consensus phase " << to_string(mLastConsensusPhase);
1105 if (mLastConsensusPhase != currPhase)
1107 reportConsensusStateChange(currPhase);
1108 mLastConsensusPhase = currPhase;
1109 CLOG(clog.
ss()) <<
" changed to " << to_string(mLastConsensusPhase);
1111 CLOG(clog.
ss()) <<
". ";
1113 setHeartbeatTimer();
1117NetworkOPsImp::processClusterTimer()
1119 if (app_.cluster().size() == 0)
1122 using namespace std::chrono_literals;
1124 bool const update = app_.cluster().update(
1125 app_.nodeIdentity().first,
1127 (m_ledgerMaster.getValidatedLedgerAge() <= 4min)
1128 ? app_.getFeeTrack().getLocalFee()
1130 app_.timeKeeper().now());
1134 JLOG(m_journal.debug()) <<
"Too soon to send cluster update";
1139 protocol::TMCluster cluster;
1140 app_.cluster().for_each([&cluster](
ClusterNode const& node) {
1141 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1146 n.set_nodename(node.
name());
1150 for (
auto& item : gossip.
items)
1152 protocol::TMLoadSource& node = *cluster.add_loadsources();
1153 node.set_name(to_string(item.address));
1154 node.set_cost(item.balance);
1156 app_.overlay().foreach(
send_if(
1157 std::make_shared<Message>(cluster, protocol::mtCLUSTER),
1168 if (mode == OperatingMode::FULL && admin)
1170 auto const consensusMode = mConsensus.mode();
1171 if (consensusMode != ConsensusMode::wrongLedger)
1173 if (consensusMode == ConsensusMode::proposing)
1176 if (mConsensus.validating())
1177 return "validating";
1187 if (isNeedNetworkLedger())
1196 auto const txid = trans->getTransactionID();
1197 auto const flags = app_.getHashRouter().getFlags(txid);
1199 if ((
flags & SF_BAD) != 0)
1201 JLOG(m_journal.warn()) <<
"Submitted transaction cached bad";
1208 app_.getHashRouter(),
1210 m_ledgerMaster.getValidatedRules(),
1213 if (validity != Validity::Valid)
1215 JLOG(m_journal.warn())
1216 <<
"Submitted transaction invalid: " << reason;
1222 JLOG(m_journal.warn())
1223 <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1230 auto tx = std::make_shared<Transaction>(trans, reason, app_);
1232 m_job_queue.addJob(
jtTRANSACTION,
"submitTxn", [
this, tx]() {
1234 processTransaction(t,
false,
false, FailHard::no);
1241 auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
1243 if ((newFlags & SF_BAD) != 0)
1246 JLOG(m_journal.warn()) << transaction->getID() <<
": cached bad!\n";
1247 transaction->setStatus(
INVALID);
1255 auto const view = m_ledgerMaster.getCurrentLedger();
1257 app_.getHashRouter(),
1258 *transaction->getSTransaction(),
1262 validity == Validity::Valid,
1263 "ripple::NetworkOPsImp::processTransaction : valid validity");
1266 if (validity == Validity::SigBad)
1268 JLOG(m_journal.info()) <<
"Transaction has bad signature: " << reason;
1269 transaction->setStatus(
INVALID);
1271 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
1276 app_.getMasterTransaction().canonicalize(&transaction);
1282NetworkOPsImp::processTransaction(
1288 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXN");
1291 if (!preProcessTransaction(transaction))
1295 doTransactionSync(transaction, bUnlimited, failType);
1297 doTransactionAsync(transaction, bUnlimited, failType);
1301NetworkOPsImp::doTransactionAsync(
1308 if (transaction->getApplying())
1311 mTransactions.push_back(
1313 transaction->setApplying();
1315 if (mDispatchState == DispatchState::none)
1317 if (m_job_queue.addJob(
1318 jtBATCH,
"transactionBatch", [
this]() { transactionBatch(); }))
1320 mDispatchState = DispatchState::scheduled;
1326NetworkOPsImp::doTransactionSync(
1333 if (!transaction->getApplying())
1335 mTransactions.push_back(
1337 transaction->setApplying();
1340 doTransactionSyncBatch(
1342 return transaction->getApplying();
1347NetworkOPsImp::doTransactionSyncBatch(
1353 if (mDispatchState == DispatchState::running)
1362 if (mTransactions.size())
1365 if (m_job_queue.addJob(
jtBATCH,
"transactionBatch", [
this]() {
1369 mDispatchState = DispatchState::scheduled;
1373 }
while (retryCallback(lock));
1379 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXNSet");
1382 for (
auto const& [_, tx] :
set)
1385 auto transaction = std::make_shared<Transaction>(tx, reason, app_);
1387 if (transaction->getStatus() ==
INVALID)
1389 if (!reason.
empty())
1391 JLOG(m_journal.trace())
1392 <<
"Exception checking transaction: " << reason;
1394 app_.getHashRouter().setFlags(tx->getTransactionID(), SF_BAD);
1399 if (!preProcessTransaction(transaction))
1410 for (
auto& transaction : candidates)
1412 if (!transaction->getApplying())
1414 transactions.
emplace_back(transaction,
false,
false, FailHard::no);
1415 transaction->setApplying();
1419 if (mTransactions.empty())
1420 mTransactions.swap(transactions);
1423 mTransactions.reserve(mTransactions.size() + transactions.
size());
1424 for (
auto& t : transactions)
1425 mTransactions.push_back(std::move(t));
1431 "ripple::NetworkOPsImp::processTransactionSet has lock");
1433 mTransactions.begin(), mTransactions.end(), [](
auto const& t) {
1434 return t.transaction->getApplying();
1440NetworkOPsImp::transactionBatch()
1444 if (mDispatchState == DispatchState::running)
1447 while (mTransactions.size())
1458 mTransactions.
swap(transactions);
1460 !transactions.
empty(),
1461 "ripple::NetworkOPsImp::apply : non-empty transactions");
1463 mDispatchState != DispatchState::running,
1464 "ripple::NetworkOPsImp::apply : is not running");
1466 mDispatchState = DispatchState::running;
1472 bool changed =
false;
1475 m_ledgerMaster.peekMutex(), std::defer_lock};
1486 if (e.failType == FailHard::yes)
1489 auto const result = app_.getTxQ().apply(
1490 app_, view, e.transaction->getSTransaction(),
flags, j);
1491 e.result = result.ter;
1492 e.applied = result.applied;
1493 changed = changed || result.applied;
1502 if (
auto const l = m_ledgerMaster.getValidatedLedger())
1503 validatedLedgerIndex = l->info().seq;
1505 auto newOL = app_.openLedger().current();
1508 e.transaction->clearSubmitResult();
1512 pubProposedTransaction(
1513 newOL, e.transaction->getSTransaction(), e.result);
1514 e.transaction->setApplied();
1517 e.transaction->setResult(e.result);
1520 app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
1529 JLOG(m_journal.info())
1530 <<
"TransactionResult: " << token <<
": " << human;
1535 bool addLocal = e.local;
1539 JLOG(m_journal.debug())
1540 <<
"Transaction is now included in open ledger";
1541 e.transaction->setStatus(
INCLUDED);
1546 auto const& txCur = e.transaction->getSTransaction();
1549 for (
auto txNext = m_ledgerMaster.popAcctTransaction(txCur);
1551 txNext = m_ledgerMaster.popAcctTransaction(txCur), ++count)
1557 auto t = std::make_shared<Transaction>(trans, reason, app_);
1558 if (t->getApplying())
1560 submit_held.
emplace_back(t,
false,
false, FailHard::no);
1569 JLOG(m_journal.info()) <<
"Transaction is obsolete";
1570 e.transaction->setStatus(
OBSOLETE);
1574 JLOG(m_journal.debug())
1575 <<
"Transaction is likely to claim a"
1576 <<
" fee, but is queued until fee drops";
1578 e.transaction->setStatus(
HELD);
1582 m_ledgerMaster.addHeldTransaction(e.transaction);
1583 e.transaction->setQueued();
1584 e.transaction->setKept();
1590 if (e.failType != FailHard::yes)
1592 auto const lastLedgerSeq =
1593 e.transaction->getSTransaction()->at(
1594 ~sfLastLedgerSequence);
1595 auto const ledgersLeft = lastLedgerSeq
1597 m_ledgerMaster.getCurrentLedgerIndex()
1615 (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) ||
1616 app_.getHashRouter().setFlags(
1617 e.transaction->getID(), SF_HELD))
1620 JLOG(m_journal.debug())
1621 <<
"Transaction should be held: " << e.result;
1622 e.transaction->setStatus(
HELD);
1623 m_ledgerMaster.addHeldTransaction(e.transaction);
1624 e.transaction->setKept();
1627 JLOG(m_journal.debug())
1628 <<
"Not holding transaction "
1629 << e.transaction->getID() <<
": "
1630 << (e.local ?
"local" :
"network") <<
", "
1631 <<
"result: " << e.result <<
" ledgers left: "
1632 << (ledgersLeft ? to_string(*ledgersLeft)
1638 JLOG(m_journal.debug())
1639 <<
"Status other than success " << e.result;
1640 e.transaction->setStatus(
INVALID);
1643 auto const enforceFailHard =
1644 e.failType == FailHard::yes && !
isTesSuccess(e.result);
1646 if (addLocal && !enforceFailHard)
1648 m_localTX->push_back(
1649 m_ledgerMaster.getCurrentLedgerIndex(),
1650 e.transaction->getSTransaction());
1651 e.transaction->setKept();
1655 ((mMode != OperatingMode::FULL) &&
1656 (e.failType != FailHard::yes) && e.local) ||
1661 app_.getHashRouter().shouldRelay(e.transaction->getID());
1665 protocol::TMTransaction tx;
1668 e.transaction->getSTransaction()->add(s);
1669 tx.set_rawtransaction(s.
data(), s.
size());
1670 tx.set_status(protocol::tsCURRENT);
1671 tx.set_receivetimestamp(
1672 app_.timeKeeper().now().time_since_epoch().count());
1675 app_.overlay().relay(e.transaction->getID(), tx, *toSkip);
1676 e.transaction->setBroadcast();
1680 if (validatedLedgerIndex)
1682 auto [
fee, accountSeq, availableSeq] =
1683 app_.getTxQ().getTxRequiredFeeAndSeq(
1684 *newOL, e.transaction->getSTransaction());
1685 e.transaction->setCurrentLedgerState(
1686 *validatedLedgerIndex,
fee, accountSeq, availableSeq);
1694 e.transaction->clearApplying();
1696 if (!submit_held.
empty())
1698 if (mTransactions.empty())
1699 mTransactions.swap(submit_held);
1702 mTransactions.reserve(mTransactions.size() + submit_held.
size());
1703 for (
auto& e : submit_held)
1704 mTransactions.push_back(std::move(e));
1710 mDispatchState = DispatchState::none;
1718NetworkOPsImp::getOwnerInfo(
1723 auto root = keylet::ownerDir(account);
1724 auto sleNode = lpLedger->read(keylet::page(
root));
1731 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1733 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
1736 "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1738 switch (sleCur->getType())
1741 if (!jvObjects.
isMember(jss::offers))
1742 jvObjects[jss::offers] =
1745 jvObjects[jss::offers].
append(
1746 sleCur->getJson(JsonOptions::none));
1749 case ltRIPPLE_STATE:
1750 if (!jvObjects.
isMember(jss::ripple_lines))
1752 jvObjects[jss::ripple_lines] =
1756 jvObjects[jss::ripple_lines].
append(
1757 sleCur->getJson(JsonOptions::none));
1760 case ltACCOUNT_ROOT:
1764 "ripple::NetworkOPsImp::getOwnerInfo : invalid "
1770 uNodeDir = sleNode->getFieldU64(sfIndexNext);
1774 sleNode = lpLedger->read(keylet::page(
root, uNodeDir));
1777 "ripple::NetworkOPsImp::getOwnerInfo : read next page");
1790NetworkOPsImp::isBlocked()
1792 return isAmendmentBlocked() || isUNLBlocked();
1796NetworkOPsImp::isAmendmentBlocked()
1798 return amendmentBlocked_;
1802NetworkOPsImp::setAmendmentBlocked()
1804 amendmentBlocked_ =
true;
1805 setMode(OperatingMode::CONNECTED);
1809NetworkOPsImp::isAmendmentWarned()
1811 return !amendmentBlocked_ && amendmentWarned_;
1815NetworkOPsImp::setAmendmentWarned()
1817 amendmentWarned_ =
true;
1821NetworkOPsImp::clearAmendmentWarned()
1823 amendmentWarned_ =
false;
1827NetworkOPsImp::isUNLBlocked()
1833NetworkOPsImp::setUNLBlocked()
1836 setMode(OperatingMode::CONNECTED);
1840NetworkOPsImp::clearUNLBlocked()
1842 unlBlocked_ =
false;
1846NetworkOPsImp::checkLastClosedLedger(
1855 JLOG(m_journal.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
1857 auto const ourClosed = m_ledgerMaster.getClosedLedger();
1862 uint256 closedLedger = ourClosed->info().hash;
1863 uint256 prevClosedLedger = ourClosed->info().parentHash;
1864 JLOG(m_journal.trace()) <<
"OurClosed: " << closedLedger;
1865 JLOG(m_journal.trace()) <<
"PrevClosed: " << prevClosedLedger;
1870 auto& validations = app_.getValidations();
1871 JLOG(m_journal.debug())
1872 <<
"ValidationTrie " <<
Json::Compact(validations.getJsonTrie());
1876 peerCounts[closedLedger] = 0;
1877 if (mMode >= OperatingMode::TRACKING)
1878 peerCounts[closedLedger]++;
1880 for (
auto& peer : peerList)
1882 uint256 peerLedger = peer->getClosedLedgerHash();
1885 ++peerCounts[peerLedger];
1888 for (
auto const& it : peerCounts)
1889 JLOG(m_journal.debug()) <<
"L: " << it.first <<
" n=" << it.second;
1891 uint256 preferredLCL = validations.getPreferredLCL(
1893 m_ledgerMaster.getValidLedgerIndex(),
1896 bool switchLedgers = preferredLCL != closedLedger;
1898 closedLedger = preferredLCL;
1900 if (switchLedgers && (closedLedger == prevClosedLedger))
1903 JLOG(m_journal.info()) <<
"We won't switch to our own previous ledger";
1904 networkClosed = ourClosed->info().hash;
1905 switchLedgers =
false;
1908 networkClosed = closedLedger;
1913 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
1916 consensus = app_.getInboundLedgers().acquire(
1917 closedLedger, 0, InboundLedger::Reason::CONSENSUS);
1920 (!m_ledgerMaster.canBeCurrent(consensus) ||
1921 !m_ledgerMaster.isCompatible(
1922 *consensus, m_journal.debug(),
"Not switching")))
1926 networkClosed = ourClosed->info().hash;
1930 JLOG(m_journal.warn()) <<
"We are not running on the consensus ledger";
1931 JLOG(m_journal.info()) <<
"Our LCL: " << ourClosed->info().hash
1933 JLOG(m_journal.info()) <<
"Net LCL " << closedLedger;
1935 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
1937 setMode(OperatingMode::CONNECTED);
1945 switchLastClosedLedger(consensus);
1952NetworkOPsImp::switchLastClosedLedger(
1956 JLOG(m_journal.error())
1957 <<
"JUMP last closed ledger to " << newLCL->info().hash;
1959 clearNeedNetworkLedger();
1962 app_.getTxQ().processClosedLedger(app_, *newLCL,
true);
1969 auto retries = m_localTX->getTxSet();
1970 auto const lastVal = app_.getLedgerMaster().getValidatedLedger();
1975 rules.
emplace(app_.config().features);
1976 app_.openLedger().accept(
1987 return app_.getTxQ().accept(app_, view);
1991 m_ledgerMaster.switchLCL(newLCL);
1993 protocol::TMStatusChange s;
1994 s.set_newevent(protocol::neSWITCHED_LEDGER);
1995 s.set_ledgerseq(newLCL->info().seq);
1996 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
1997 s.set_ledgerhashprevious(
1998 newLCL->info().parentHash.begin(), newLCL->info().parentHash.size());
1999 s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size());
2001 app_.overlay().foreach(
2002 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
2006NetworkOPsImp::beginConsensus(
2012 "ripple::NetworkOPsImp::beginConsensus : nonzero input");
2014 auto closingInfo = m_ledgerMaster.getCurrentLedger()->info();
2016 JLOG(m_journal.info()) <<
"Consensus time for #" << closingInfo.seq
2017 <<
" with LCL " << closingInfo.parentHash;
2019 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
2024 if (mMode == OperatingMode::FULL)
2026 JLOG(m_journal.warn()) <<
"Don't have LCL, going to tracking";
2027 setMode(OperatingMode::TRACKING);
2028 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
2031 CLOG(clog) <<
"beginConsensus no previous ledger. ";
2036 prevLedger->info().hash == closingInfo.parentHash,
2037 "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches "
2040 closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash,
2041 "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches "
2044 if (prevLedger->rules().enabled(featureNegativeUNL))
2045 app_.validators().setNegativeUNL(prevLedger->negativeUNL());
2046 TrustChanges const changes = app_.validators().updateTrusted(
2047 app_.getValidations().getCurrentNodeIDs(),
2048 closingInfo.parentCloseTime,
2051 app_.getHashRouter());
2053 if (!changes.
added.empty() || !changes.
removed.empty())
2055 app_.getValidations().trustChanged(changes.
added, changes.
removed);
2057 app_.getAmendmentTable().trustChanged(
2058 app_.validators().getQuorumKeys().second);
2061 mConsensus.startRound(
2062 app_.timeKeeper().closeTime(),
2070 if (mLastConsensusPhase != currPhase)
2072 reportConsensusStateChange(currPhase);
2073 mLastConsensusPhase = currPhase;
2076 JLOG(m_journal.debug()) <<
"Initiating consensus engine";
2083 auto const& peerKey = peerPos.
publicKey();
2084 if (validatorPK_ == peerKey || validatorMasterPK_ == peerKey)
2095 JLOG(m_journal.error())
2096 <<
"Received a proposal signed by MY KEY from a peer. This may "
2097 "indicate a misconfiguration where another node has the same "
2098 "validator key, or may be caused by unusual message routing and "
2103 return mConsensus.peerProposal(app_.timeKeeper().closeTime(), peerPos);
2114 protocol::TMHaveTransactionSet msg;
2115 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
2116 msg.set_status(protocol::tsHAVE);
2117 app_.overlay().foreach(
2118 send_always(std::make_shared<Message>(msg, protocol::mtHAVE_SET)));
2122 mConsensus.gotTxSet(app_.timeKeeper().closeTime(),
RCLTxSet{map});
2128 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash;
2130 for (
auto const& it : app_.overlay().getActivePeers())
2132 if (it && (it->getClosedLedgerHash() == deadLedger))
2134 JLOG(m_journal.trace()) <<
"Killing obsolete peer status";
2141 checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed);
2143 if (networkClosed.
isZero())
2145 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
2155 if (((mMode == OperatingMode::CONNECTED) ||
2156 (mMode == OperatingMode::SYNCING)) &&
2162 if (!needNetworkLedger_)
2163 setMode(OperatingMode::TRACKING);
2166 if (((mMode == OperatingMode::CONNECTED) ||
2167 (mMode == OperatingMode::TRACKING)) &&
2173 auto current = m_ledgerMaster.getCurrentLedger();
2174 if (app_.timeKeeper().now() < (
current->info().parentCloseTime +
2175 2 *
current->info().closeTimeResolution))
2177 setMode(OperatingMode::FULL);
2181 beginConsensus(networkClosed, clog);
2185NetworkOPsImp::consensusViewChange()
2187 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
2189 setMode(OperatingMode::CONNECTED);
2199 if (!mStreamMaps[sManifests].empty())
2203 jvObj[jss::type] =
"manifestReceived";
2206 jvObj[jss::signing_key] =
2213 jvObj[jss::domain] = mo.
domain;
2216 for (
auto i = mStreamMaps[sManifests].begin();
2217 i != mStreamMaps[sManifests].end();)
2219 if (
auto p = i->second.lock())
2221 p->send(jvObj,
true);
2226 i = mStreamMaps[sManifests].erase(i);
2232NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
2236 : loadFactorServer{loadFeeTrack.getLoadFactor()}
2237 , loadBaseServer{loadFeeTrack.getLoadBase()}
2239 , em{
std::move(escalationMetrics)}
2249 em.has_value() != b.
em.has_value())
2255 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2256 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2257 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2290 jvObj[jss::type] =
"serverStatus";
2292 jvObj[jss::load_base] = f.loadBaseServer;
2293 jvObj[jss::load_factor_server] = f.loadFactorServer;
2294 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
2299 safe_cast<std::uint64_t>(f.loadFactorServer),
2301 f.em->openLedgerFeeLevel,
2303 f.em->referenceFeeLevel)
2306 jvObj[jss::load_factor] =
trunc32(loadFactor);
2307 jvObj[jss::load_factor_fee_escalation] =
2308 f.em->openLedgerFeeLevel.jsonClipped();
2309 jvObj[jss::load_factor_fee_queue] =
2310 f.em->minProcessingFeeLevel.jsonClipped();
2311 jvObj[jss::load_factor_fee_reference] =
2312 f.em->referenceFeeLevel.jsonClipped();
2315 jvObj[jss::load_factor] = f.loadFactorServer;
2329 p->send(jvObj,
true);
2346 if (!streamMap.empty())
2349 jvObj[jss::type] =
"consensusPhase";
2350 jvObj[jss::consensus] =
to_string(phase);
2352 for (
auto i = streamMap.begin(); i != streamMap.end();)
2354 if (
auto p = i->second.lock())
2356 p->send(jvObj,
true);
2361 i = streamMap.erase(i);
2377 auto const signerPublic = val->getSignerPublic();
2379 jvObj[jss::type] =
"validationReceived";
2380 jvObj[jss::validation_public_key] =
2382 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2383 jvObj[jss::signature] =
strHex(val->getSignature());
2384 jvObj[jss::full] = val->isFull();
2385 jvObj[jss::flags] = val->getFlags();
2386 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2387 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2389 if (
auto version = (*val)[~sfServerVersion])
2392 if (
auto cookie = (*val)[~sfCookie])
2395 if (
auto hash = (*val)[~sfValidatedHash])
2396 jvObj[jss::validated_hash] =
strHex(*hash);
2398 auto const masterKey =
2401 if (masterKey != signerPublic)
2406 if (
auto const seq = (*val)[~sfLedgerSequence])
2407 jvObj[jss::ledger_index] = *
seq;
2409 if (val->isFieldPresent(sfAmendments))
2412 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2416 if (
auto const closeTime = (*val)[~sfCloseTime])
2417 jvObj[jss::close_time] = *closeTime;
2419 if (
auto const loadFee = (*val)[~sfLoadFee])
2420 jvObj[jss::load_fee] = *loadFee;
2422 if (
auto const baseFee = val->at(~sfBaseFee))
2423 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2425 if (
auto const reserveBase = val->at(~sfReserveBase))
2426 jvObj[jss::reserve_base] = *reserveBase;
2428 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2429 jvObj[jss::reserve_inc] = *reserveInc;
2433 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops);
2434 baseFeeXRP && baseFeeXRP->native())
2435 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2437 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
2438 reserveBaseXRP && reserveBaseXRP->native())
2439 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2441 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
2442 reserveIncXRP && reserveIncXRP->native())
2443 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2452 if (jvTx.
isMember(jss::ledger_index))
2454 jvTx[jss::ledger_index] =
2455 std::to_string(jvTx[jss::ledger_index].asUInt());
2462 if (
auto p = i->second.lock())
2466 [&](
Json::Value const& jv) { p->send(jv, true); });
2486 jvObj[jss::type] =
"peerStatusChange";
2495 p->send(jvObj,
true);
2509 using namespace std::chrono_literals;
2541 <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2557 <<
"Exception thrown for handling new validation "
2558 << val->getLedgerHash() <<
": " << e.
what();
2563 <<
"Unknown exception thrown for handling new validation "
2564 << val->getLedgerHash();
2576 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2613 "This server is amendment blocked, and must be updated to be "
2614 "able to stay in sync with the network.";
2621 "This server has an expired validator list. validators.txt "
2622 "may be incorrectly configured or some [validator_list_sites] "
2623 "may be unreachable.";
2630 "One or more unsupported amendments have reached majority. "
2631 "Upgrade to the latest version before they are activated "
2632 "to avoid being amendment blocked.";
2633 if (
auto const expected =
2637 d[jss::expected_date] = expected->time_since_epoch().count();
2638 d[jss::expected_date_UTC] =
to_string(*expected);
2642 if (warnings.size())
2643 info[jss::warnings] = std::move(warnings);
2658 info[jss::time] =
to_string(std::chrono::floor<std::chrono::microseconds>(
2662 info[jss::network_ledger] =
"waiting";
2664 info[jss::validation_quorum] =
2672 info[jss::node_size] =
"tiny";
2675 info[jss::node_size] =
"small";
2678 info[jss::node_size] =
"medium";
2681 info[jss::node_size] =
"large";
2684 info[jss::node_size] =
"huge";
2693 info[jss::validator_list_expires] =
2694 safe_cast<Json::UInt>(when->time_since_epoch().count());
2696 info[jss::validator_list_expires] = 0;
2706 if (*when == TimeKeeper::time_point::max())
2708 x[jss::expiration] =
"never";
2709 x[jss::status] =
"active";
2716 x[jss::status] =
"active";
2718 x[jss::status] =
"expired";
2723 x[jss::status] =
"unknown";
2724 x[jss::expiration] =
"unknown";
2728#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH)
2731#ifdef GIT_COMMIT_HASH
2732 x[jss::hash] = GIT_COMMIT_HASH;
2735 x[jss::branch] = GIT_BRANCH;
2740 info[jss::io_latency_ms] =
2748 info[jss::pubkey_validator] =
2753 info[jss::pubkey_validator] =
"none";
2763 info[jss::counters][jss::nodestore] = nodestore;
2767 info[jss::pubkey_node] =
2773 info[jss::amendment_blocked] =
true;
2787 lastClose[jss::converge_time_s] =
2792 lastClose[jss::converge_time] =
2796 info[jss::last_close] = lastClose;
2804 info[jss::network_id] =
static_cast<Json::UInt>(*netid);
2806 auto const escalationMetrics =
2814 auto const loadFactorFeeEscalation =
2816 escalationMetrics.openLedgerFeeLevel,
2818 escalationMetrics.referenceFeeLevel)
2822 safe_cast<std::uint64_t>(loadFactorServer), loadFactorFeeEscalation);
2826 info[jss::load_base] = loadBaseServer;
2827 info[jss::load_factor] =
trunc32(loadFactor);
2828 info[jss::load_factor_server] = loadFactorServer;
2835 info[jss::load_factor_fee_escalation] =
2836 escalationMetrics.openLedgerFeeLevel.jsonClipped();
2837 info[jss::load_factor_fee_queue] =
2838 escalationMetrics.minProcessingFeeLevel.jsonClipped();
2839 info[jss::load_factor_fee_reference] =
2840 escalationMetrics.referenceFeeLevel.jsonClipped();
2844 info[jss::load_factor] =
2845 static_cast<double>(loadFactor) / loadBaseServer;
2847 if (loadFactorServer != loadFactor)
2848 info[jss::load_factor_server] =
2849 static_cast<double>(loadFactorServer) / loadBaseServer;
2854 if (
fee != loadBaseServer)
2855 info[jss::load_factor_local] =
2856 static_cast<double>(
fee) / loadBaseServer;
2858 if (
fee != loadBaseServer)
2859 info[jss::load_factor_net] =
2860 static_cast<double>(
fee) / loadBaseServer;
2862 if (
fee != loadBaseServer)
2863 info[jss::load_factor_cluster] =
2864 static_cast<double>(
fee) / loadBaseServer;
2866 if (escalationMetrics.openLedgerFeeLevel !=
2867 escalationMetrics.referenceFeeLevel &&
2868 (admin || loadFactorFeeEscalation != loadFactor))
2869 info[jss::load_factor_fee_escalation] =
2870 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
2871 escalationMetrics.referenceFeeLevel);
2872 if (escalationMetrics.minProcessingFeeLevel !=
2873 escalationMetrics.referenceFeeLevel)
2874 info[jss::load_factor_fee_queue] =
2875 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
2876 escalationMetrics.referenceFeeLevel);
2889 XRPAmount const baseFee = lpClosed->fees().base;
2891 l[jss::seq] =
Json::UInt(lpClosed->info().seq);
2892 l[jss::hash] =
to_string(lpClosed->info().hash);
2897 l[jss::reserve_base] =
2898 lpClosed->fees().accountReserve(0).jsonClipped();
2899 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
2901 lpClosed->info().closeTime.time_since_epoch().count());
2906 l[jss::reserve_base_xrp] =
2907 lpClosed->fees().accountReserve(0).decimalXRP();
2908 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
2911 std::abs(closeOffset.count()) >= 60)
2912 l[jss::close_time_offset] =
2920 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2924 auto lCloseTime = lpClosed->info().closeTime;
2926 if (lCloseTime <= closeTime)
2928 using namespace std::chrono_literals;
2929 auto age = closeTime - lCloseTime;
2931 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2937 info[jss::validated_ledger] = l;
2939 info[jss::closed_ledger] = l;
2943 info[jss::published_ledger] =
"none";
2944 else if (lpPublished->info().seq != lpClosed->info().seq)
2945 info[jss::published_ledger] = lpPublished->info().seq;
2950 info[jss::jq_trans_overflow] =
2952 info[jss::peer_disconnects] =
2954 info[jss::peer_disconnects_resources] =
2959 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
2967 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
2968 port.admin_user.empty() && port.admin_password.empty()))
2982 for (
auto const& p : proto)
2983 jv[jss::protocol].append(p);
2990 auto const optPort = grpcSection.
get(
"port");
2991 if (optPort && grpcSection.get(
"ip"))
2994 jv[jss::port] = *optPort;
2996 jv[jss::protocol].append(
"grpc");
2999 info[jss::ports] = std::move(ports);
3024 transJson(transaction, result,
false, ledger, std::nullopt);
3038 [&](
Json::Value const& jv) { p->send(jv, true); });
3061 alpAccepted = std::make_shared<AcceptedLedger>(lpAccepted,
app_);
3063 lpAccepted->info().hash, alpAccepted);
3067 alpAccepted->getLedger().
get() == lpAccepted.
get(),
3068 "ripple::NetworkOPsImp::pubLedger : accepted input");
3072 <<
"Publishing ledger " << lpAccepted->info().seq <<
" "
3073 << lpAccepted->info().hash;
3081 jvObj[jss::type] =
"ledgerClosed";
3082 jvObj[jss::ledger_index] = lpAccepted->info().seq;
3083 jvObj[jss::ledger_hash] =
to_string(lpAccepted->info().hash);
3085 lpAccepted->info().closeTime.time_since_epoch().count());
3087 if (!lpAccepted->rules().enabled(featureXRPFees))
3089 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
3090 jvObj[jss::reserve_base] =
3091 lpAccepted->fees().accountReserve(0).jsonClipped();
3092 jvObj[jss::reserve_inc] =
3093 lpAccepted->fees().increment.jsonClipped();
3095 jvObj[jss::txn_count] =
Json::UInt(alpAccepted->size());
3099 jvObj[jss::validated_ledgers] =
3109 p->send(jvObj,
true);
3127 p->send(jvObj,
true);
3136 static bool firstTime =
true;
3143 for (
auto& inner : outer.second)
3145 auto& subInfo = inner.second;
3146 if (subInfo.index_->separationLedgerSeq_ == 0)
3149 alpAccepted->getLedger(), subInfo);
3158 for (
auto const& accTx : *alpAccepted)
3162 lpAccepted, *accTx, accTx == *(--alpAccepted->end()));
3189 "reportConsensusStateChange->pubConsensus",
3220 jvObj[jss::type] =
"transaction";
3224 jvObj[jss::transaction] =
3231 jvObj[jss::meta], *ledger, transaction, meta->
get());
3233 jvObj[jss::meta], transaction, meta->
get());
3237 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
3238 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
3240 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
3242 if (transaction->isFieldPresent(sfNetworkID))
3243 netID = transaction->getFieldU32(sfNetworkID);
3248 jvObj[jss::ctid] = *ctid;
3250 if (!ledger->open())
3251 jvObj[jss::ledger_hash] =
to_string(ledger->info().hash);
3255 jvObj[jss::ledger_index] = ledger->info().seq;
3256 jvObj[jss::transaction][jss::date] =
3257 ledger->info().closeTime.time_since_epoch().count();
3258 jvObj[jss::validated] =
true;
3259 jvObj[jss::close_time_iso] =
to_string_iso(ledger->info().closeTime);
3265 jvObj[jss::validated] =
false;
3266 jvObj[jss::ledger_current_index] = ledger->info().seq;
3269 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3270 jvObj[jss::engine_result] = sToken;
3271 jvObj[jss::engine_result_code] = result;
3272 jvObj[jss::engine_result_message] = sHuman;
3274 if (transaction->getTxnType() == ttOFFER_CREATE)
3276 auto const account = transaction->getAccountID(sfAccount);
3277 auto const amount = transaction->getFieldAmount(sfTakerGets);
3280 if (account != amount.issue().account)
3288 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3296 [&]<
unsigned Version>(
3298 RPC::insertDeliverMax(
3299 jvTx[jss::transaction], transaction->getTxnType(), Version);
3301 if constexpr (Version > 1)
3303 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3304 jvTx[jss::hash] = hash;
3308 jvTx[jss::transaction][jss::hash] = hash;
3321 auto const& stTxn = transaction.
getTxn();
3325 auto const trResult = transaction.
getResult();
3340 [&](
Json::Value const& jv) { p->send(jv, true); });
3357 [&](
Json::Value const& jv) { p->send(jv, true); });
3382 auto const currLedgerSeq = ledger->seq();
3389 for (
auto const& affectedAccount : transaction.
getAffected())
3394 auto it = simiIt->second.begin();
3396 while (it != simiIt->second.end())
3407 it = simiIt->second.erase(it);
3414 auto it = simiIt->second.begin();
3415 while (it != simiIt->second.end())
3426 it = simiIt->second.erase(it);
3433 auto& subs = histoIt->second;
3434 auto it = subs.begin();
3435 while (it != subs.end())
3438 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
3452 it = subs.erase(it);
3463 <<
"pubAccountTransaction: "
3464 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3466 if (!notify.
empty() || !accountHistoryNotify.
empty())
3468 auto const& stTxn = transaction.
getTxn();
3472 auto const trResult = transaction.
getResult();
3478 isrListener->getApiVersion(),
3479 [&](
Json::Value const& jv) { isrListener->send(jv, true); });
3483 jvObj.
set(jss::account_history_boundary,
true);
3486 jvObj.
isMember(jss::account_history_tx_stream) ==
3488 "ripple::NetworkOPsImp::pubAccountTransaction : "
3489 "account_history_tx_stream not set");
3490 for (
auto& info : accountHistoryNotify)
3492 auto& index = info.index_;
3493 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3494 jvObj.
set(jss::account_history_tx_first,
true);
3496 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3499 info.sink_->getApiVersion(),
3500 [&](
Json::Value const& jv) { info.sink_->send(jv, true); });
3525 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3530 auto it = simiIt->second.begin();
3532 while (it != simiIt->second.end())
3543 it = simiIt->second.erase(it);
3550 JLOG(
m_journal.
trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3552 if (!notify.
empty() || !accountHistoryNotify.
empty())
3559 isrListener->getApiVersion(),
3560 [&](
Json::Value const& jv) { isrListener->send(jv, true); });
3563 jvObj.
isMember(jss::account_history_tx_stream) ==
3565 "ripple::NetworkOPs::pubProposedAccountTransaction : "
3566 "account_history_tx_stream not set");
3567 for (
auto& info : accountHistoryNotify)
3569 auto& index = info.index_;
3570 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3571 jvObj.
set(jss::account_history_tx_first,
true);
3572 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3574 info.sink_->getApiVersion(),
3575 [&](
Json::Value const& jv) { info.sink_->send(jv, true); });
3592 for (
auto const& naAccountID : vnaAccountIDs)
3595 <<
"subAccount: account: " <<
toBase58(naAccountID);
3597 isrListener->insertSubAccountInfo(naAccountID, rt);
3602 for (
auto const& naAccountID : vnaAccountIDs)
3604 auto simIterator = subMap.
find(naAccountID);
3605 if (simIterator == subMap.
end())
3609 usisElement[isrListener->getSeq()] = isrListener;
3611 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3616 simIterator->second[isrListener->getSeq()] = isrListener;
3627 for (
auto const& naAccountID : vnaAccountIDs)
3630 isrListener->deleteSubAccountInfo(naAccountID, rt);
3647 for (
auto const& naAccountID : vnaAccountIDs)
3649 auto simIterator = subMap.
find(naAccountID);
3651 if (simIterator != subMap.
end())
3654 simIterator->second.erase(uSeq);
3656 if (simIterator->second.empty())
3659 subMap.
erase(simIterator);
3668 enum DatabaseType { Sqlite,
None };
3669 static auto const databaseType = [&]() -> DatabaseType {
3674 return DatabaseType::Sqlite;
3676 return DatabaseType::None;
3679 if (databaseType == DatabaseType::None)
3682 <<
"AccountHistory job for account "
3694 "AccountHistoryTxStream",
3695 [
this, dbType = databaseType, subInfo]() {
3696 auto const& accountId = subInfo.
index_->accountId_;
3697 auto& lastLedgerSeq = subInfo.
index_->historyLastLedgerSeq_;
3698 auto& txHistoryIndex = subInfo.
index_->historyTxIndex_;
3701 <<
"AccountHistory job for account " <<
toBase58(accountId)
3702 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
3712 auto stx = tx->getSTransaction();
3713 if (stx->getAccountID(sfAccount) == accountId &&
3714 stx->getSeqValue() == 1)
3718 for (
auto& node : meta->getNodes())
3720 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
3723 if (node.isFieldPresent(sfNewFields))
3725 if (
auto inner =
dynamic_cast<STObject const*
>(
3726 node.peekAtPField(sfNewFields));
3729 if (inner->isFieldPresent(sfAccount) &&
3730 inner->getAccountID(sfAccount) == accountId)
3742 bool unsubscribe) ->
bool {
3745 sptr->send(jvObj,
true);
3755 bool unsubscribe) ->
bool {
3759 sptr->getApiVersion(),
3760 [&](
Json::Value const& jv) { sptr->send(jv,
true); });
3783 accountId, minLedger, maxLedger, marker, 0,
true};
3784 return db->newestAccountTxPage(options);
3788 "ripple::NetworkOPsImp::addAccountHistoryJob::"
3789 "getMoreTxns : invalid database type");
3798 while (lastLedgerSeq >= 2 && !subInfo.
index_->stopHistorical_)
3800 int feeChargeCount = 0;
3809 <<
"AccountHistory job for account "
3810 <<
toBase58(accountId) <<
" no InfoSub. Fee charged "
3811 << feeChargeCount <<
" times.";
3816 auto startLedgerSeq =
3817 (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
3819 <<
"AccountHistory job for account " <<
toBase58(accountId)
3820 <<
", working on ledger range [" << startLedgerSeq <<
","
3821 << lastLedgerSeq <<
"]";
3823 auto haveRange = [&]() ->
bool {
3826 auto haveSomeValidatedLedgers =
3828 validatedMin, validatedMax);
3830 return haveSomeValidatedLedgers &&
3831 validatedMin <= startLedgerSeq &&
3832 lastLedgerSeq <= validatedMax;
3838 <<
"AccountHistory reschedule job for account "
3839 <<
toBase58(accountId) <<
", incomplete ledger range ["
3840 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3846 while (!subInfo.
index_->stopHistorical_)
3849 getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
3853 <<
"AccountHistory job for account "
3854 <<
toBase58(accountId) <<
" getMoreTxns failed.";
3859 auto const& txns = dbResult->first;
3860 marker = dbResult->second;
3861 size_t num_txns = txns.size();
3862 for (
size_t i = 0; i < num_txns; ++i)
3864 auto const& [tx, meta] = txns[i];
3869 <<
"AccountHistory job for account "
3870 <<
toBase58(accountId) <<
" empty tx or meta.";
3880 <<
"AccountHistory job for account "
3881 <<
toBase58(accountId) <<
" no ledger.";
3886 tx->getSTransaction();
3890 <<
"AccountHistory job for account "
3892 <<
" getSTransaction failed.";
3898 auto const trR = meta->getResultTER();
3900 transJson(stTxn, trR,
true, curTxLedger, mRef);
3903 jss::account_history_tx_index, txHistoryIndex--);
3904 if (i + 1 == num_txns ||
3905 txns[i + 1].first->getLedger() != tx->getLedger())
3906 jvTx.
set(jss::account_history_boundary,
true);
3908 if (isFirstTx(tx, meta))
3910 jvTx.
set(jss::account_history_tx_first,
true);
3911 sendMultiApiJson(jvTx,
false);
3914 <<
"AccountHistory job for account "
3916 <<
" done, found last tx.";
3921 sendMultiApiJson(jvTx,
false);
3928 <<
"AccountHistory job for account "
3930 <<
" paging, marker=" << marker->ledgerSeq <<
":"
3939 if (!subInfo.
index_->stopHistorical_)
3941 lastLedgerSeq = startLedgerSeq - 1;
3942 if (lastLedgerSeq <= 1)
3945 <<
"AccountHistory job for account "
3947 <<
" done, reached genesis ledger.";
3960 subInfo.
index_->separationLedgerSeq_ = ledger->seq();
3961 auto const& accountId = subInfo.
index_->accountId_;
3963 if (!ledger->exists(accountKeylet))
3966 <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
3967 <<
", no need to add AccountHistory job.";
3972 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
3974 if (sleAcct->getFieldU32(sfSequence) == 1)
3977 <<
"subAccountHistoryStart, genesis account "
3979 <<
" does not have tx, no need to add AccountHistory job.";
3986 "ripple::NetworkOPsImp::subAccountHistoryStart : failed to "
3987 "access genesis account");
3991 subInfo.
index_->historyLastLedgerSeq_ = ledger->seq();
3992 subInfo.
index_->haveHistorical_ =
true;
3995 <<
"subAccountHistoryStart, add AccountHistory job: accountId="
3996 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
4006 if (!isrListener->insertSubAccountHistory(accountId))
4009 <<
"subAccountHistory, already subscribed to account "
4016 isrListener, std::make_shared<SubAccountHistoryIndex>(accountId)};
4021 inner.
emplace(isrListener->getSeq(), ahi);
4027 simIterator->second.emplace(isrListener->getSeq(), ahi);
4041 <<
"subAccountHistory, no validated ledger yet, delay start";
4054 isrListener->deleteSubAccountHistory(account);
4068 auto& subInfoMap = simIterator->second;
4069 auto subInfoIter = subInfoMap.find(
seq);
4070 if (subInfoIter != subInfoMap.end())
4072 subInfoIter->second.index_->stopHistorical_ =
true;
4077 simIterator->second.erase(
seq);
4078 if (simIterator->second.empty())
4084 <<
"unsubAccountHistory, account " <<
toBase58(account)
4085 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
4093 listeners->addSubscriber(isrListener);
4095 UNREACHABLE(
"ripple::NetworkOPsImp::subBook : null book listeners");
4103 listeners->removeSubscriber(uSeq);
4115 m_standalone,
"ripple::NetworkOPsImp::acceptLedger : is standalone");
4118 Throw<std::runtime_error>(
4119 "Operation only possible in STANDALONE mode.");
4134 jvResult[jss::ledger_index] = lpClosed->info().seq;
4135 jvResult[jss::ledger_hash] =
to_string(lpClosed->info().hash);
4137 lpClosed->info().closeTime.time_since_epoch().count());
4138 if (!lpClosed->rules().enabled(featureXRPFees))
4140 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
4141 jvResult[jss::reserve_base] =
4142 lpClosed->fees().accountReserve(0).jsonClipped();
4143 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
4148 jvResult[jss::validated_ledgers] =
4154 .emplace(isrListener->getSeq(), isrListener)
4164 .emplace(isrListener->getSeq(), isrListener)
4190 .emplace(isrListener->getSeq(), isrListener)
4218 jvResult[jss::random] =
to_string(uRandom);
4220 jvResult[jss::load_base] = feeTrack.getLoadBase();
4221 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4222 jvResult[jss::hostid] =
getHostId(admin);
4223 jvResult[jss::pubkey_node] =
4228 .emplace(isrListener->getSeq(), isrListener)
4246 .emplace(isrListener->getSeq(), isrListener)
4264 .emplace(isrListener->getSeq(), isrListener)
4282 .emplace(isrListener->getSeq(), isrListener)
4306 .emplace(isrListener->getSeq(), isrListener)
4324 .emplace(isrListener->getSeq(), isrListener)
4372 if (map.find(pInfo->getSeq()) != map.end())
4379#ifndef USE_NEW_BOOK_PAGE
4390 unsigned int iLimit,
4400 uint256 uTipIndex = uBookBase;
4404 stream <<
"getBookPage:" << book;
4405 stream <<
"getBookPage: uBookBase=" << uBookBase;
4406 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4407 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4416 bool bDirectAdvance =
true;
4420 unsigned int uBookEntry;
4426 while (!bDone && iLimit-- > 0)
4430 bDirectAdvance =
false;
4434 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4438 sleOfferDir.
reset();
4447 uTipIndex = sleOfferDir->key();
4450 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4453 <<
"getBookPage: uTipIndex=" << uTipIndex;
4455 <<
"getBookPage: offerIndex=" << offerIndex;
4465 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4466 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4467 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4469 bool firstOwnerOffer(
true);
4475 saOwnerFunds = saTakerGets;
4477 else if (bGlobalFreeze)
4485 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4486 if (umBalanceEntry != umBalance.
end())
4490 saOwnerFunds = umBalanceEntry->second;
4491 firstOwnerOffer =
false;
4505 if (saOwnerFunds < beast::zero)
4509 saOwnerFunds.
clear();
4517 STAmount saOwnerFundsLimit = saOwnerFunds;
4529 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4532 if (saOwnerFundsLimit >= saTakerGets)
4535 saTakerGetsFunded = saTakerGets;
4541 saTakerGetsFunded = saOwnerFundsLimit;
4543 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4547 saTakerGetsFunded, saDirRate, saTakerPays.
issue()))
4548 .setJson(jvOffer[jss::taker_pays_funded]);
4554 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4556 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4560 jvOf[jss::quality] = saDirRate.
getText();
4562 if (firstOwnerOffer)
4563 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4570 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4572 bDirectAdvance =
true;
4577 <<
"getBookPage: offerIndex=" << offerIndex;
4597 unsigned int iLimit,
4605 MetaView lesActive(lpLedger,
tapNONE,
true);
4606 OrderBookIterator obIterator(lesActive, book);
4610 bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.
out.
account) ||
4611 lesActive.isGlobalFrozen(book.
in.
account);
4613 while (iLimit-- > 0 && obIterator.nextOffer())
4618 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4619 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4620 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4621 STAmount saDirRate = obIterator.getCurrentRate();
4627 saOwnerFunds = saTakerGets;
4629 else if (bGlobalFreeze)
4637 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4639 if (umBalanceEntry != umBalance.
end())
4643 saOwnerFunds = umBalanceEntry->second;
4649 saOwnerFunds = lesActive.accountHolds(
4655 if (saOwnerFunds.isNegative())
4659 saOwnerFunds.zero();
4666 STAmount saTakerGetsFunded;
4667 STAmount saOwnerFundsLimit = saOwnerFunds;
4679 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4682 if (saOwnerFundsLimit >= saTakerGets)
4685 saTakerGetsFunded = saTakerGets;
4690 saTakerGetsFunded = saOwnerFundsLimit;
4692 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
4698 multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
4699 .setJson(jvOffer[jss::taker_pays_funded]);
4702 STAmount saOwnerPays = (
parityRate == offerRate)
4705 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4707 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4709 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
4713 jvOf[jss::quality] = saDirRate.
getText();
4728 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4768 ++counters_[
static_cast<std::size_t>(om)].transitions;
4770 counters_[
static_cast<std::size_t>(om)].transitions == 1)
4772 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(
4773 now - processStart_)
4777 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
4786 auto [counters, mode, start, initialSync] = getCounterData();
4787 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4797 auto& state = obj[jss::state_accounting][
states_[i]];
4798 state[jss::transitions] =
std::to_string(counters[i].transitions);
4799 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
4803 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
4818 boost::asio::io_service& io_svc,
4822 return std::make_unique<NetworkOPsImp>(
T back_inserter(T... args)
Decorator for streaming out compact json.
Lightweight wrapper to tag static string.
Value & append(Value const &value)
Append value to array at the end.
bool isMember(char const *key) const
Return true if the object has a member named key.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
A metric for measuring an integral value.
void set(value_type value) const
Set the value on the gauge.
A reference to a handler for performing polled collection.
A transaction that is in a closed ledger.
boost::container::flat_set< AccountID > const & getAffected() const
std::shared_ptr< STTx const > const & getTxn() const
TxMeta const & getMeta() const
virtual std::optional< NetClock::time_point > firstUnsupportedExpected() const =0
virtual Config & config()=0
virtual Overlay & overlay()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual OpenLedger & openLedger()=0
virtual beast::Journal journal(std::string const &name)=0
virtual NodeStore::Database & getNodeStore()=0
virtual ServerHandler & getServerHandler()=0
virtual std::chrono::milliseconds getIOLatency()=0
virtual OrderBookDB & getOrderBookDB()=0
virtual TimeKeeper & timeKeeper()=0
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
virtual JobQueue & getJobQueue()=0
virtual InboundLedgers & getInboundLedgers()=0
virtual ValidatorList & validators()=0
virtual std::optional< PublicKey const > getValidationPublicKey() const =0
virtual LedgerMaster & getLedgerMaster()=0
virtual RelationalDatabase & getRelationalDatabase()=0
virtual ManifestCache & validatorManifests()=0
virtual perf::PerfLog & getPerfLog()=0
virtual Cluster & cluster()=0
virtual AmendmentTable & getAmendmentTable()=0
virtual std::pair< PublicKey, SecretKey > const & nodeIdentity()=0
bool exists(std::string const &name) const
Returns true if a section with the given name exists.
Section & section(std::string const &name)
Returns the section with the given name.
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::string const & name() const
std::uint32_t getLoadFee() const
NetClock::time_point getReportTime() const
PublicKey const & identity() const
std::size_t size() const
The number of nodes in the cluster list.
std::string SERVER_DOMAIN
static constexpr std::uint32_t FEE_UNITS_DEPRECATED
int RELAY_UNTRUSTED_VALIDATIONS
virtual void clearFailures()=0
virtual Json::Value getInfo()=0
std::shared_ptr< InfoSub > pointer
A pool of threads to perform work.
Json::Value getJson(int c=0)
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
std::shared_ptr< Ledger const > getValidatedLedger()
bool haveValidated()
Whether we have ever fully validated a ledger.
std::shared_ptr< ReadView const > getCurrentLedger()
bool getValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
std::shared_ptr< Ledger const > getClosedLedger()
std::string getCompleteLedgers()
std::size_t getFetchPackCacheSize() const
std::shared_ptr< ReadView const > getPublishedLedger()
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
std::chrono::seconds getValidatedLedgerAge()
Manages the current fee schedule.
std::uint32_t getClusterFee() const
std::uint32_t getLocalFee() const
std::uint32_t getLoadBase() const
std::uint32_t getRemoteFee() const
std::uint32_t getLoadFactor() const
void heartbeat()
Reset the stall detection timer.
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
State accounting records two attributes for each possible server state: 1) Amount of time spent in ea...
void mode(OperatingMode om)
Record state transition.
void json(Json::Value &obj) const
Output state counters in JSON format.
std::array< Counters, 5 > counters_
std::uint64_t initialSyncUs_
CounterData getCounterData() const
std::chrono::steady_clock::time_point start_
static std::array< Json::StaticString const, 5 > const states_
std::chrono::steady_clock::time_point const processStart_
Transaction with input flags and results to be applied in batches.
TransactionStatus(std::shared_ptr< Transaction > t, bool a, bool l, FailHard f)
std::shared_ptr< Transaction > const transaction
void processClusterTimer()
boost::asio::steady_timer accountHistoryTxTimer_
void pubProposedTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result) override
OperatingMode getOperatingMode() const override
std::string strOperatingMode(OperatingMode const mode, bool const admin) const override
bool preProcessTransaction(std::shared_ptr< Transaction > &transaction)
std::vector< TransactionStatus > mTransactions
bool unsubBookChanges(std::uint64_t uListener) override
std::atomic< OperatingMode > mMode
Json::Value getLedgerFetchInfo() override
bool isUNLBlocked() override
void unsubAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Json::Value getOwnerInfo(std::shared_ptr< ReadView const > lpLedger, AccountID const &account) override
void setNeedNetworkLedger() override
void setUNLBlocked() override
void pubConsensus(ConsensusPhase phase)
void transactionBatch()
Apply transactions in batches.
void apply(std::unique_lock< std::mutex > &batchLock)
Attempt to apply transactions and post-process based on the results.
void setAmendmentBlocked() override
bool checkLastClosedLedger(Overlay::PeerSequence const &, uint256 &networkClosed)
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.
void processTransactionSet(CanonicalTXSet const &set) override
Process a set of transactions synchronously, and ensuring that they are processed in one batch.
void clearUNLBlocked() override
boost::asio::steady_timer heartbeatTimer_
void updateLocalTx(ReadView const &view) override
bool unsubManifests(std::uint64_t uListener) override
DispatchState
Synchronization states for transaction batches.
std::optional< PublicKey > const validatorPK_
bool unsubTransactions(std::uint64_t uListener) override
void clearAmendmentWarned() override
std::size_t getLocalTxCount() override
std::unique_ptr< LocalTxs > m_localTX
bool subValidations(InfoSub::ref ispListener) override
bool subLedger(InfoSub::ref ispListener, Json::Value &jvResult) override
~NetworkOPsImp() override
bool isAmendmentBlocked() override
void unsubAccountHistoryInternal(std::uint64_t seq, AccountID const &account, bool historyOnly) override
SubAccountHistoryMapType mSubAccountHistory
Json::Value getServerInfo(bool human, bool admin, bool counters) override
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::ref) override
boost::asio::steady_timer clusterTimer_
bool isAmendmentWarned() override
static std::array< char const *, 5 > const states_
bool subServer(InfoSub::ref ispListener, Json::Value &jvResult, bool admin) override
NetworkOPsImp(Application &app, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool start_valid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_service &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
void unsubAccountInternal(std::uint64_t seq, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
std::atomic< bool > amendmentBlocked_
SubInfoMapType mSubAccount
std::optional< PublicKey > const validatorMasterPK_
void unsubAccountHistory(InfoSub::ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
std::set< uint256 > pendingValidations_
bool beginConsensus(uint256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
bool unsubValidations(std::uint64_t uListener) override
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
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 setTimer(boost::asio::steady_timer &timer, std::chrono::milliseconds const &expiry_time, std::function< void()> onExpire, std::function< void()> onError)
std::array< SubMapType, SubTypes::sLastEntry > mStreamMaps
bool unsubPeerStatus(std::uint64_t uListener) override
void pubValidation(std::shared_ptr< STValidation > const &val) override
std::size_t const minPeerCount_
std::atomic< bool > unlBlocked_
bool subBook(InfoSub::ref ispListener, Book const &) override
std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay) override
Accepts the current transaction tree, return the new ledger's sequence.
void stateAccounting(Json::Value &obj) override
void submitTransaction(std::shared_ptr< STTx const > const &) override
bool unsubRTTransactions(std::uint64_t uListener) override
Json::Value getConsensusInfo() override
std::recursive_mutex mSubLock
std::atomic< bool > needNetworkLedger_
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
void switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
StateAccounting accounting_
void reportConsensusStateChange(ConsensusPhase phase)
bool subConsensus(InfoSub::ref ispListener) override
bool isNeedNetworkLedger() override
void setAmendmentWarned() override
bool processTrustedProposal(RCLCxPeerPos proposal) override
void doTransactionSyncBatch(std::unique_lock< std::mutex > &lock, std::function< bool(std::unique_lock< std::mutex > const &)> retryCallback)
bool subPeerStatus(InfoSub::ref ispListener) override
void mapComplete(std::shared_ptr< SHAMap > const &map, bool fromAcquire) override
bool tryRemoveRpcSub(std::string const &strUrl) override
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
LedgerMaster & m_ledgerMaster
void clearLedgerFetch() override
bool isBlocked() override
void consensusViewChange() override
void setStateTimer() override
Called to initially start our timers.
bool subManifests(InfoSub::ref ispListener) override
void pubValidatedTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
void subAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
bool unsubServer(std::uint64_t uListener) override
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)
ServerFeeSummary mLastFeeSummary
void pubPeerStatus(std::function< Json::Value(void)> const &) override
void setStandAlone() override
bool subRTTransactions(InfoSub::ref ispListener) override
void pubProposedAccountTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result)
std::condition_variable mCond
void setMode(OperatingMode om) 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
void clearNeedNetworkLedger() override
DispatchState mDispatchState
bool subBookChanges(InfoSub::ref ispListener) override
SubInfoMapType mSubRTAccount
void reportFeeChange() override
void processHeartbeatTimer()
bool unsubBook(std::uint64_t uListener, Book const &) override
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
error_code_i subAccountHistory(InfoSub::ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
std::mutex validationsMutex_
void pubManifest(Manifest const &) override
ConsensusPhase mLastConsensusPhase
bool subTransactions(InfoSub::ref ispListener) override
std::atomic< bool > amendmentWarned_
InfoSub::pointer findRpcSub(std::string const &strUrl) override
bool unsubLedger(std::uint64_t uListener) override
std::string getHostId(bool forAdmin)
bool unsubConsensus(std::uint64_t uListener) override
Provides server functionality for clients.
void getCountsJson(Json::Value &obj)
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Writable ledger view that accumulates state and tx changes.
BookListeners::pointer getBookListeners(Book const &)
void processTxn(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &alTx, MultiApiJson const &jvObj)
BookListeners::pointer makeBookListeners(Book const &)
virtual std::optional< std::uint32_t > networkID() const =0
Returns the ID of the network this server is configured for, if any.
virtual std::uint64_t getPeerDisconnect() const =0
virtual std::size_t size() const =0
Returns the number of active peers.
virtual std::uint64_t getJqTransOverflow() const =0
virtual std::uint64_t getPeerDisconnectCharges() const =0
Manages the generic consensus algorithm for use by the RCL.
std::size_t prevProposers() const
Get the number of proposing peers that participated in the previous round.
void simulate(NetClock::time_point const &now, std::optional< std::chrono::milliseconds > consensusDelay)
std::chrono::milliseconds prevRoundTime() const
Get duration of the previous round.
Json::Value getJson(bool full) const
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 std::shared_ptr< SLE const > 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.
void setJson(Json::Value &) const
std::string getText() const override
Issue const & issue() const
std::optional< T > get(std::string const &name) const
std::size_t size() const noexcept
void const * data() const noexcept
void setup(Setup const &setup, beast::Journal journal)
time_point now() const override
Returns the current time, using the server's clock.
std::chrono::seconds closeOffset() const
time_point closeTime() const
Returns the predicted close time, in network time.
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Validator keys and manifest as set in configuration file.
std::size_t count() const
Return the number of configured validator list sites.
std::optional< PublicKey > getTrustedKey(PublicKey const &identity) const
Returns master public key if public key is trusted.
std::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
std::size_t quorum() const
Get quorum value for current trusted key set.
constexpr double decimalXRP() const
Json::Value jsonClipped() const
static constexpr std::size_t size()
virtual Json::Value currentJson() const =0
Render currently executing jobs and RPC calls and durations in Json.
virtual Json::Value countersJson() const =0
Render performance counters in Json.
Automatically unlocks and re-locks a unique_lock object.
Set the regular signature on a JTx.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
void rngfill(void *buffer, std::size_t bytes, Generator &g)
std::string const & getVersionString()
Server version.
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
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.
Charge const feeMediumBurdenRPC
TER valid(PreclaimContext const &ctx, AccountID const &src)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
STAmount divide(STAmount const &amount, Rate const &rate)
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool cdirFirst(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the first entry in the directory, advancing the index.
std::uint64_t getQuality(uint256 const &uBase)
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
auto constexpr muldiv_max
std::unique_ptr< LocalTxs > make_LocalTxs()
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
STAmount amountFromQuality(std::uint64_t rate)
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.
std::unique_ptr< NetworkOPs > make_NetworkOPs(Application &app, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool startvalid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_service &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
@ warnRPC_EXPIRED_VALIDATOR_LIST
@ warnRPC_UNSUPPORTED_MAJORITY
@ warnRPC_AMENDMENT_BLOCKED
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,...
std::unique_ptr< FeeVote > make_FeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
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
STAmount multiply(STAmount const &amount, Rate const &rate)
AccountID calcAccountID(PublicKey const &pk)
@ current
This was a new validation and was added.
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
Json::Value rpcError(int iError)
ConsensusPhase
Phases of consensus for a single ledger round.
static std::array< char const *, 5 > const stateNames
std::string strHex(FwdIt begin, FwdIt end)
bool isTemMalformed(TER x)
bool cdirNext(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the next entry in the directory, advancing the index.
void forAllApiVersions(Fn const &fn, Args &&... args)
send_if_pred< Predicate > send_if(std::shared_ptr< Message > const &m, Predicate const &f)
Helper function to aid in type deduction.
uint256 getQualityNext(uint256 const &uBase)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Rules makeRulesGivenLedger(DigestAwareReadView const &ledger, Rules const ¤t)
std::string to_string_iso(date::sys_time< Duration > tp)
std::string to_string(base_uint< Bits, Tag > const &a)
FeeSetup setup_FeeVote(Section const §ion)
Number root(Number f, unsigned d)
std::optional< std::uint64_t > mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
Return value*mul/div accurately.
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
@ ledgerMaster
ledger master data for signing
@ proposal
proposal for signing
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
constexpr std::size_t maxPoppedTransactions
bool transResultInfo(TER code, std::string &token, std::string &text)
uint256 getBookBase(Book const &book)
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
static std::uint32_t trunc32(std::uint64_t v)
static auto const genesisAccountId
T set_intersection(T... args)
std::string serialized
The manifest in serialized form.
std::uint32_t sequence
The sequence number of this manifest.
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.
Blob getMasterSignature() const
Returns manifest master key signature.
PublicKey masterKey
The master key associated with this manifest.
Server fees published on server subscription.
bool operator!=(ServerFeeSummary const &b) const
ServerFeeSummary()=default
std::optional< TxQ::Metrics > em
std::uint32_t loadFactorServer
bool operator==(ServerFeeSummary const &b) const
std::uint32_t loadBaseServer
decltype(initialSyncUs_) initialSyncUs
decltype(counters_) counters
std::uint64_t transitions
std::chrono::microseconds dur
beast::insight::Gauge full_transitions
Stats(Handler const &handler, beast::insight::Collector::ptr const &collector)
beast::insight::Hook hook
beast::insight::Gauge connected_duration
beast::insight::Gauge tracking_duration
beast::insight::Gauge connected_transitions
beast::insight::Gauge disconnected_transitions
beast::insight::Gauge syncing_duration
beast::insight::Gauge tracking_transitions
beast::insight::Gauge full_duration
beast::insight::Gauge disconnected_duration
beast::insight::Gauge syncing_transitions
std::uint32_t historyLastLedgerSeq_
std::uint32_t separationLedgerSeq_
AccountID const accountId_
std::uint32_t forwardTxIndex_
std::atomic< bool > stopHistorical_
std::int32_t historyTxIndex_
SubAccountHistoryIndex(AccountID const &accountId)
std::shared_ptr< SubAccountHistoryIndex > index_
std::shared_ptr< SubAccountHistoryIndex > index_
Represents a transfer rate.
Data format for exchanging consumption information across peers.
std::vector< Item > items
Changes in trusted nodes after updating validator list.
hash_set< NodeID > removed
Structure returned by TxQ::getMetrics, expressed in reference fee level units.
IsMemberResult isMember(char const *key) const
void set(char const *key, auto const &v)
Select all peers (except optional excluded) that are in our cluster.
Sends a message to all peers.
Set the sequence number on a JTx.
T time_since_epoch(T... args)