1#include <xrpld/app/consensus/RCLConsensus.h>
2#include <xrpld/app/consensus/RCLCxPeerPos.h>
3#include <xrpld/app/consensus/RCLValidations.h>
4#include <xrpld/app/ledger/AcceptedLedger.h>
5#include <xrpld/app/ledger/InboundLedgers.h>
6#include <xrpld/app/ledger/LedgerMaster.h>
7#include <xrpld/app/ledger/LedgerToJson.h>
8#include <xrpld/app/ledger/LocalTxs.h>
9#include <xrpld/app/ledger/OpenLedger.h>
10#include <xrpld/app/ledger/TransactionMaster.h>
11#include <xrpld/app/main/LoadManager.h>
12#include <xrpld/app/main/Tuning.h>
13#include <xrpld/app/misc/AmendmentTable.h>
14#include <xrpld/app/misc/DeliverMax.h>
15#include <xrpld/app/misc/LoadFeeTrack.h>
16#include <xrpld/app/misc/Transaction.h>
17#include <xrpld/app/misc/TxQ.h>
18#include <xrpld/app/misc/ValidatorKeys.h>
19#include <xrpld/app/misc/ValidatorList.h>
20#include <xrpld/app/misc/detail/AccountTxPaging.h>
21#include <xrpld/app/misc/make_NetworkOPs.h>
22#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
23#include <xrpld/app/tx/apply.h>
24#include <xrpld/consensus/Consensus.h>
25#include <xrpld/consensus/ConsensusParms.h>
26#include <xrpld/overlay/Cluster.h>
27#include <xrpld/overlay/Overlay.h>
28#include <xrpld/overlay/predicates.h>
29#include <xrpld/rpc/BookChanges.h>
30#include <xrpld/rpc/CTID.h>
31#include <xrpld/rpc/DeliveredAmount.h>
32#include <xrpld/rpc/MPTokenIssuanceID.h>
33#include <xrpld/rpc/ServerHandler.h>
35#include <xrpl/basics/UptimeClock.h>
36#include <xrpl/basics/mulDiv.h>
37#include <xrpl/basics/safe_cast.h>
38#include <xrpl/basics/scope.h>
39#include <xrpl/beast/utility/rngfill.h>
40#include <xrpl/core/HashRouter.h>
41#include <xrpl/core/PerfLog.h>
42#include <xrpl/crypto/RFC1751.h>
43#include <xrpl/crypto/csprng.h>
44#include <xrpl/ledger/OrderBookDB.h>
45#include <xrpl/protocol/BuildInfo.h>
46#include <xrpl/protocol/Feature.h>
47#include <xrpl/protocol/MultiApiJson.h>
48#include <xrpl/protocol/NFTSyntheticSerializer.h>
49#include <xrpl/protocol/RPCErr.h>
50#include <xrpl/protocol/TxFlags.h>
51#include <xrpl/protocol/jss.h>
52#include <xrpl/resource/Fees.h>
53#include <xrpl/resource/ResourceManager.h>
55#include <boost/asio/ip/host_name.hpp>
56#include <boost/asio/steady_timer.hpp>
91 "xrpl::NetworkOPsImp::TransactionStatus::TransactionStatus : "
190 return !(*
this != b);
209 boost::asio::io_context& io_svc,
226 registry.getInboundTransactions(),
227 beast::get_abstract_clock<
std::chrono::steady_clock>(),
229 registry_.logs().journal(
"LedgerConsensus"))
410 getServerInfo(
bool human,
bool admin,
bool counters)
override;
436 TER result)
override;
531 catch (boost::system::system_error
const& e)
533 JLOG(
m_journal.
error()) <<
"NetworkOPs: heartbeatTimer cancel error: " << e.what();
540 catch (boost::system::system_error
const& e)
542 JLOG(
m_journal.
error()) <<
"NetworkOPs: clusterTimer cancel error: " << e.what();
549 catch (boost::system::system_error
const& e)
551 JLOG(
m_journal.
error()) <<
"NetworkOPs: accountHistoryTxTimer cancel error: " << e.what();
555 using namespace std::chrono_literals;
565 boost::asio::steady_timer& timer,
745 template <
class Handler>
747 :
hook(collector->make_hook(handler))
750 ,
syncing_duration(collector->make_gauge(
"State_Accounting",
"Syncing_duration"))
751 ,
tracking_duration(collector->make_gauge(
"State_Accounting",
"Tracking_duration"))
752 ,
full_duration(collector->make_gauge(
"State_Accounting",
"Full_duration"))
757 ,
full_transitions(collector->make_gauge(
"State_Accounting",
"Full_transitions"))
845 static std::string const hostname = boost::asio::ip::host_name();
852 static std::string const shroudedHostId = [
this]() {
858 return shroudedHostId;
873 boost::asio::steady_timer& timer,
879 if (
auto optionalCountedHandler =
881 if ((e.value() == boost::system::errc::success) && (!m_job_queue.isStopped()))
886 if (e.value() != boost::system::errc::success && e.value() != boost::asio::error::operation_aborted)
889 JLOG(m_journal.error()) <<
"Timer got error '" << e.message() <<
"'. Restarting timer.";
894 timer.expires_after(expiry_time);
895 timer.async_wait(std::move(*optionalCountedHandler));
900NetworkOPsImp::setHeartbeatTimer()
904 mConsensus.parms().ledgerGRANULARITY,
905 [
this]() { m_job_queue.addJob(jtNETOP_TIMER,
"NetHeart", [this]() { processHeartbeatTimer(); }); },
906 [
this]() { setHeartbeatTimer(); });
910NetworkOPsImp::setClusterTimer()
912 using namespace std::chrono_literals;
917 [
this]() { m_job_queue.addJob(
jtNETOP_CLUSTER,
"NetCluster", [
this]() { processClusterTimer(); }); },
918 [
this]() { setClusterTimer(); });
924 JLOG(m_journal.debug()) <<
"Scheduling AccountHistory job for account " <<
toBase58(subInfo.
index_->accountId_);
925 using namespace std::chrono_literals;
927 accountHistoryTxTimer_,
929 [
this, subInfo]() { addAccountHistoryJob(subInfo); },
930 [
this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
934NetworkOPsImp::processHeartbeatTimer()
944 std::size_t const numPeers = registry_.overlay().size();
947 if (numPeers < minPeerCount_)
949 if (mMode != OperatingMode::DISCONNECTED)
951 setMode(OperatingMode::DISCONNECTED);
953 ss <<
"Node count (" << numPeers <<
") has fallen "
954 <<
"below required minimum (" << minPeerCount_ <<
").";
955 JLOG(m_journal.warn()) << ss.
str();
956 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
960 CLOG(clog.
ss()) <<
"already DISCONNECTED. too few peers (" << numPeers <<
"), need at least "
973 if (mMode == OperatingMode::DISCONNECTED)
975 setMode(OperatingMode::CONNECTED);
976 JLOG(m_journal.info()) <<
"Node count (" << numPeers <<
") is sufficient.";
977 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers <<
" peers. ";
982 auto origMode = mMode.load();
983 CLOG(clog.
ss()) <<
"mode: " << strOperatingMode(origMode,
true);
984 if (mMode == OperatingMode::SYNCING)
985 setMode(OperatingMode::SYNCING);
986 else if (mMode == OperatingMode::CONNECTED)
987 setMode(OperatingMode::CONNECTED);
988 auto newMode = mMode.load();
989 if (origMode != newMode)
991 CLOG(clog.
ss()) <<
", changing to " << strOperatingMode(newMode,
true);
993 CLOG(clog.
ss()) <<
". ";
996 mConsensus.timerEntry(registry_.timeKeeper().closeTime(), clog.
ss());
998 CLOG(clog.
ss()) <<
"consensus phase " << to_string(mLastConsensusPhase);
1000 if (mLastConsensusPhase != currPhase)
1002 reportConsensusStateChange(currPhase);
1003 mLastConsensusPhase = currPhase;
1004 CLOG(clog.
ss()) <<
" changed to " << to_string(mLastConsensusPhase);
1006 CLOG(clog.
ss()) <<
". ";
1008 setHeartbeatTimer();
1012NetworkOPsImp::processClusterTimer()
1014 if (registry_.cluster().size() == 0)
1017 using namespace std::chrono_literals;
1019 bool const update = registry_.cluster().update(
1020 registry_.app().nodeIdentity().first,
1022 (m_ledgerMaster.getValidatedLedgerAge() <= 4min) ? registry_.getFeeTrack().getLocalFee() : 0,
1023 registry_.timeKeeper().now());
1027 JLOG(m_journal.debug()) <<
"Too soon to send cluster update";
1032 protocol::TMCluster cluster;
1033 registry_.cluster().for_each([&cluster](
ClusterNode const& node) {
1034 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1039 n.set_nodename(node.
name());
1042 Resource::Gossip gossip = registry_.getResourceManager().exportConsumers();
1043 for (
auto& item : gossip.
items)
1045 protocol::TMLoadSource& node = *cluster.add_loadsources();
1046 node.set_name(to_string(item.address));
1047 node.set_cost(item.balance);
1056NetworkOPsImp::strOperatingMode(
OperatingMode const mode,
bool const admin)
const
1058 if (mode == OperatingMode::FULL && admin)
1060 auto const consensusMode = mConsensus.mode();
1061 if (consensusMode != ConsensusMode::wrongLedger)
1063 if (consensusMode == ConsensusMode::proposing)
1066 if (mConsensus.validating())
1067 return "validating";
1077 if (isNeedNetworkLedger())
1084 if (iTrans->isFlag(
tfInnerBatchTxn) && m_ledgerMaster.getValidatedRules().enabled(featureBatch))
1086 JLOG(m_journal.error()) <<
"Submitted transaction invalid: tfInnerBatchTxn flag present.";
1093 auto const txid = trans->getTransactionID();
1094 auto const flags = registry_.getHashRouter().getFlags(txid);
1096 if ((flags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)
1098 JLOG(m_journal.warn()) <<
"Submitted transaction cached bad";
1105 registry_.getHashRouter(), *trans, m_ledgerMaster.getValidatedRules(), registry_.app().config());
1107 if (validity != Validity::Valid)
1109 JLOG(m_journal.warn()) <<
"Submitted transaction invalid: " << reason;
1115 JLOG(m_journal.warn()) <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1124 m_job_queue.addJob(
jtTRANSACTION,
"SubmitTxn", [
this, tx]() {
1126 processTransaction(t,
false,
false, FailHard::no);
1133 auto const newFlags = registry_.getHashRouter().getFlags(transaction->getID());
1135 if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)
1138 JLOG(m_journal.warn()) << transaction->getID() <<
": cached bad!\n";
1139 transaction->setStatus(
INVALID);
1144 auto const view = m_ledgerMaster.getCurrentLedger();
1149 auto const sttx = *transaction->getSTransaction();
1150 if (sttx.isFlag(
tfInnerBatchTxn) && view->rules().enabled(featureBatch))
1152 transaction->setStatus(
INVALID);
1154 registry_.getHashRouter().setFlags(transaction->getID(), HashRouterFlags::BAD);
1161 auto const [validity, reason] =
1162 checkValidity(registry_.getHashRouter(), sttx, view->rules(), registry_.app().config());
1163 XRPL_ASSERT(validity == Validity::Valid,
"xrpl::NetworkOPsImp::processTransaction : valid validity");
1166 if (validity == Validity::SigBad)
1168 JLOG(m_journal.info()) <<
"Transaction has bad signature: " << reason;
1169 transaction->setStatus(
INVALID);
1171 registry_.getHashRouter().setFlags(transaction->getID(), HashRouterFlags::BAD);
1176 registry_.getMasterTransaction().canonicalize(&transaction);
1182NetworkOPsImp::processTransaction(
1188 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXN");
1191 if (!preProcessTransaction(transaction))
1195 doTransactionSync(transaction, bUnlimited, failType);
1197 doTransactionAsync(transaction, bUnlimited, failType);
1205 if (transaction->getApplying())
1208 mTransactions.push_back(
TransactionStatus(transaction, bUnlimited,
false, failType));
1209 transaction->setApplying();
1211 if (mDispatchState == DispatchState::none)
1213 if (m_job_queue.addJob(
jtBATCH,
"TxBatchAsync", [
this]() { transactionBatch(); }))
1215 mDispatchState = DispatchState::scheduled;
1225 if (!transaction->getApplying())
1227 mTransactions.push_back(
TransactionStatus(transaction, bUnlimited,
true, failType));
1228 transaction->setApplying();
1231 doTransactionSyncBatch(
1236NetworkOPsImp::doTransactionSyncBatch(
1242 if (mDispatchState == DispatchState::running)
1251 if (mTransactions.size())
1254 if (m_job_queue.addJob(
jtBATCH,
"TxBatchSync", [
this]() { transactionBatch(); }))
1256 mDispatchState = DispatchState::scheduled;
1260 }
while (retryCallback(lock));
1266 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXNSet");
1269 for (
auto const& [_, tx] :
set)
1274 if (transaction->getStatus() ==
INVALID)
1276 if (!reason.
empty())
1278 JLOG(m_journal.trace()) <<
"Exception checking transaction: " << reason;
1280 registry_.getHashRouter().setFlags(tx->getTransactionID(), HashRouterFlags::BAD);
1285 if (!preProcessTransaction(transaction))
1296 for (
auto& transaction : candidates)
1298 if (!transaction->getApplying())
1300 transactions.
emplace_back(transaction,
false,
false, FailHard::no);
1301 transaction->setApplying();
1305 if (mTransactions.empty())
1306 mTransactions.swap(transactions);
1309 mTransactions.reserve(mTransactions.size() + transactions.
size());
1310 for (
auto& t : transactions)
1311 mTransactions.push_back(std::move(t));
1313 if (mTransactions.empty())
1315 JLOG(m_journal.debug()) <<
"No transaction to process!";
1320 XRPL_ASSERT(lock.owns_lock(),
"xrpl::NetworkOPsImp::processTransactionSet has lock");
1322 mTransactions.begin(), mTransactions.end(), [](
auto const& t) { return t.transaction->getApplying(); });
1327NetworkOPsImp::transactionBatch()
1331 if (mDispatchState == DispatchState::running)
1334 while (mTransactions.size())
1345 mTransactions.
swap(transactions);
1346 XRPL_ASSERT(!transactions.
empty(),
"xrpl::NetworkOPsImp::apply : non-empty transactions");
1347 XRPL_ASSERT(mDispatchState != DispatchState::running,
"xrpl::NetworkOPsImp::apply : is not running");
1349 mDispatchState = DispatchState::running;
1355 bool changed =
false;
1368 if (e.failType == FailHard::yes)
1372 registry_.getTxQ().apply(registry_.app(), view, e.transaction->getSTransaction(), flags, j);
1373 e.result = result.ter;
1374 e.applied = result.applied;
1375 changed = changed || result.applied;
1384 if (
auto const l = m_ledgerMaster.getValidatedLedger())
1385 validatedLedgerIndex = l->header().seq;
1387 auto newOL = registry_.openLedger().current();
1390 e.transaction->clearSubmitResult();
1394 pubProposedTransaction(newOL, e.transaction->getSTransaction(), e.result);
1395 e.transaction->setApplied();
1398 e.transaction->setResult(e.result);
1401 registry_.getHashRouter().setFlags(e.transaction->getID(), HashRouterFlags::BAD);
1410 JLOG(m_journal.info()) <<
"TransactionResult: " << token <<
": " << human;
1415 bool addLocal = e.local;
1419 JLOG(m_journal.debug()) <<
"Transaction is now included in open ledger";
1420 e.transaction->setStatus(
INCLUDED);
1425 auto const& txCur = e.transaction->getSTransaction();
1428 for (
auto txNext = m_ledgerMaster.popAcctTransaction(txCur); txNext && count <
maxPoppedTransactions;
1429 txNext = m_ledgerMaster.popAcctTransaction(txCur), ++count)
1436 if (t->getApplying())
1438 submit_held.
emplace_back(t,
false,
false, FailHard::no);
1447 JLOG(m_journal.info()) <<
"Transaction is obsolete";
1448 e.transaction->setStatus(
OBSOLETE);
1452 JLOG(m_journal.debug()) <<
"Transaction is likely to claim a"
1453 <<
" fee, but is queued until fee drops";
1455 e.transaction->setStatus(
HELD);
1459 m_ledgerMaster.addHeldTransaction(e.transaction);
1460 e.transaction->setQueued();
1461 e.transaction->setKept();
1465 if (e.failType != FailHard::yes)
1467 auto const lastLedgerSeq = e.transaction->getSTransaction()->at(~sfLastLedgerSequence);
1468 auto const ledgersLeft = lastLedgerSeq ? *lastLedgerSeq - m_ledgerMaster.getCurrentLedgerIndex()
1486 if (e.local || (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) ||
1487 registry_.getHashRouter().setFlags(e.transaction->getID(), HashRouterFlags::HELD))
1490 JLOG(m_journal.debug()) <<
"Transaction should be held: " << e.result;
1491 e.transaction->setStatus(
HELD);
1492 m_ledgerMaster.addHeldTransaction(e.transaction);
1493 e.transaction->setKept();
1496 JLOG(m_journal.debug())
1497 <<
"Not holding transaction " << e.transaction->getID() <<
": "
1498 << (e.local ?
"local" :
"network") <<
", "
1499 <<
"result: " << e.result
1500 <<
" ledgers left: " << (ledgersLeft ? to_string(*ledgersLeft) :
"unspecified");
1505 JLOG(m_journal.debug()) <<
"Status other than success " << e.result;
1506 e.transaction->setStatus(
INVALID);
1509 auto const enforceFailHard = e.failType == FailHard::yes && !
isTesSuccess(e.result);
1511 if (addLocal && !enforceFailHard)
1513 m_localTX->push_back(m_ledgerMaster.getCurrentLedgerIndex(), e.transaction->getSTransaction());
1514 e.transaction->setKept();
1517 if ((e.applied || ((mMode != OperatingMode::FULL) && (e.failType != FailHard::yes) && e.local) ||
1521 auto const toSkip = registry_.getHashRouter().shouldRelay(e.transaction->getID());
1522 if (
auto const sttx = *(e.transaction->getSTransaction()); toSkip &&
1529 protocol::TMTransaction tx;
1533 tx.set_rawtransaction(s.
data(), s.
size());
1534 tx.set_status(protocol::tsCURRENT);
1535 tx.set_receivetimestamp(registry_.timeKeeper().now().time_since_epoch().count());
1538 registry_.overlay().relay(e.transaction->getID(), tx, *toSkip);
1539 e.transaction->setBroadcast();
1543 if (validatedLedgerIndex)
1545 auto [fee, accountSeq, availableSeq] =
1546 registry_.getTxQ().getTxRequiredFeeAndSeq(*newOL, e.transaction->getSTransaction());
1547 e.transaction->setCurrentLedgerState(*validatedLedgerIndex, fee, accountSeq, availableSeq);
1555 e.transaction->clearApplying();
1557 if (!submit_held.
empty())
1559 if (mTransactions.empty())
1560 mTransactions.swap(submit_held);
1563 mTransactions.reserve(mTransactions.size() + submit_held.
size());
1564 for (
auto& e : submit_held)
1565 mTransactions.push_back(std::move(e));
1571 mDispatchState = DispatchState::none;
1582 auto root = keylet::ownerDir(account);
1583 auto sleNode = lpLedger->read(keylet::page(
root));
1590 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1592 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
1593 XRPL_ASSERT(sleCur,
"xrpl::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1595 switch (sleCur->getType())
1598 if (!jvObjects.
isMember(jss::offers))
1601 jvObjects[jss::offers].
append(sleCur->getJson(JsonOptions::none));
1604 case ltRIPPLE_STATE:
1605 if (!jvObjects.
isMember(jss::ripple_lines))
1610 jvObjects[jss::ripple_lines].
append(sleCur->getJson(JsonOptions::none));
1613 case ltACCOUNT_ROOT:
1618 "xrpl::NetworkOPsImp::getOwnerInfo : invalid "
1625 uNodeDir = sleNode->getFieldU64(sfIndexNext);
1629 sleNode = lpLedger->read(keylet::page(
root, uNodeDir));
1630 XRPL_ASSERT(sleNode,
"xrpl::NetworkOPsImp::getOwnerInfo : read next page");
1643NetworkOPsImp::isBlocked()
1645 return isAmendmentBlocked() || isUNLBlocked();
1649NetworkOPsImp::isAmendmentBlocked()
1651 return amendmentBlocked_;
1655NetworkOPsImp::setAmendmentBlocked()
1657 amendmentBlocked_ =
true;
1658 setMode(OperatingMode::CONNECTED);
1662NetworkOPsImp::isAmendmentWarned()
1664 return !amendmentBlocked_ && amendmentWarned_;
1668NetworkOPsImp::setAmendmentWarned()
1670 amendmentWarned_ =
true;
1674NetworkOPsImp::clearAmendmentWarned()
1676 amendmentWarned_ =
false;
1680NetworkOPsImp::isUNLBlocked()
1686NetworkOPsImp::setUNLBlocked()
1689 setMode(OperatingMode::CONNECTED);
1693NetworkOPsImp::clearUNLBlocked()
1695 unlBlocked_ =
false;
1706 JLOG(m_journal.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
1708 auto const ourClosed = m_ledgerMaster.getClosedLedger();
1713 uint256 closedLedger = ourClosed->header().hash;
1714 uint256 prevClosedLedger = ourClosed->header().parentHash;
1715 JLOG(m_journal.trace()) <<
"OurClosed: " << closedLedger;
1716 JLOG(m_journal.trace()) <<
"PrevClosed: " << prevClosedLedger;
1721 auto& validations = registry_.getValidations();
1722 JLOG(m_journal.debug()) <<
"ValidationTrie " <<
Json::Compact(validations.getJsonTrie());
1726 peerCounts[closedLedger] = 0;
1727 if (mMode >= OperatingMode::TRACKING)
1728 peerCounts[closedLedger]++;
1730 for (
auto& peer : peerList)
1732 uint256 peerLedger = peer->getClosedLedgerHash();
1735 ++peerCounts[peerLedger];
1738 for (
auto const& it : peerCounts)
1739 JLOG(m_journal.debug()) <<
"L: " << it.first <<
" n=" << it.second;
1741 uint256 preferredLCL = validations.getPreferredLCL(
1743 m_ledgerMaster.getValidLedgerIndex(),
1746 bool switchLedgers = preferredLCL != closedLedger;
1748 closedLedger = preferredLCL;
1750 if (switchLedgers && (closedLedger == prevClosedLedger))
1753 JLOG(m_journal.info()) <<
"We won't switch to our own previous ledger";
1754 networkClosed = ourClosed->header().hash;
1755 switchLedgers =
false;
1758 networkClosed = closedLedger;
1763 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
1766 consensus = registry_.getInboundLedgers().acquire(closedLedger, 0, InboundLedger::Reason::CONSENSUS);
1769 (!m_ledgerMaster.canBeCurrent(consensus) ||
1770 !m_ledgerMaster.isCompatible(*consensus, m_journal.debug(),
"Not switching")))
1774 networkClosed = ourClosed->header().hash;
1778 JLOG(m_journal.warn()) <<
"We are not running on the consensus ledger";
1779 JLOG(m_journal.info()) <<
"Our LCL: " << ourClosed->header().hash <<
getJson({*ourClosed, {}});
1780 JLOG(m_journal.info()) <<
"Net LCL " << closedLedger;
1782 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
1784 setMode(OperatingMode::CONNECTED);
1792 switchLastClosedLedger(consensus);
1802 JLOG(m_journal.error()) <<
"JUMP last closed ledger to " << newLCL->header().hash;
1804 clearNeedNetworkLedger();
1807 registry_.getTxQ().processClosedLedger(registry_.app(), *newLCL,
true);
1814 auto retries = m_localTX->getTxSet();
1815 auto const lastVal = registry_.getLedgerMaster().getValidatedLedger();
1820 rules.
emplace(registry_.app().config().features);
1821 registry_.openLedger().accept(
1832 return registry_.getTxQ().accept(registry_.app(), view);
1836 m_ledgerMaster.switchLCL(newLCL);
1838 protocol::TMStatusChange s;
1839 s.set_newevent(protocol::neSWITCHED_LEDGER);
1840 s.set_ledgerseq(newLCL->header().seq);
1841 s.set_networktime(registry_.timeKeeper().now().time_since_epoch().count());
1842 s.set_ledgerhashprevious(newLCL->header().parentHash.begin(), newLCL->header().parentHash.size());
1843 s.set_ledgerhash(newLCL->header().hash.begin(), newLCL->header().hash.size());
1851 XRPL_ASSERT(networkClosed.
isNonZero(),
"xrpl::NetworkOPsImp::beginConsensus : nonzero input");
1853 auto closingInfo = m_ledgerMaster.getCurrentLedger()->header();
1855 JLOG(m_journal.info()) <<
"Consensus time for #" << closingInfo.seq <<
" with LCL " << closingInfo.parentHash;
1857 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
1862 if (mMode == OperatingMode::FULL)
1864 JLOG(m_journal.warn()) <<
"Don't have LCL, going to tracking";
1865 setMode(OperatingMode::TRACKING);
1866 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
1869 CLOG(clog) <<
"beginConsensus no previous ledger. ";
1874 prevLedger->header().hash == closingInfo.parentHash,
1875 "xrpl::NetworkOPsImp::beginConsensus : prevLedger hash matches "
1878 closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->header().hash,
1879 "xrpl::NetworkOPsImp::beginConsensus : closedLedger parent matches "
1882 registry_.validators().setNegativeUNL(prevLedger->negativeUNL());
1883 TrustChanges const changes = registry_.validators().updateTrusted(
1884 registry_.getValidations().getCurrentNodeIDs(),
1885 closingInfo.parentCloseTime,
1887 registry_.overlay(),
1888 registry_.getHashRouter());
1890 if (!changes.
added.empty() || !changes.
removed.empty())
1892 registry_.getValidations().trustChanged(changes.
added, changes.
removed);
1894 registry_.getAmendmentTable().trustChanged(registry_.validators().getQuorumKeys().second);
1897 mConsensus.startRound(
1898 registry_.timeKeeper().closeTime(), networkClosed, prevLedger, changes.
removed, changes.
added, clog);
1901 if (mLastConsensusPhase != currPhase)
1903 reportConsensusStateChange(currPhase);
1904 mLastConsensusPhase = currPhase;
1907 JLOG(m_journal.debug()) <<
"Initiating consensus engine";
1914 auto const& peerKey = peerPos.
publicKey();
1915 if (validatorPK_ == peerKey || validatorMasterPK_ == peerKey)
1926 JLOG(m_journal.error()) <<
"Received a proposal signed by MY KEY from a peer. This may "
1927 "indicate a misconfiguration where another node has the same "
1928 "validator key, or may be caused by unusual message routing and "
1933 return mConsensus.peerProposal(registry_.timeKeeper().closeTime(), peerPos);
1944 protocol::TMHaveTransactionSet msg;
1945 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
1946 msg.set_status(protocol::tsHAVE);
1951 mConsensus.gotTxSet(registry_.timeKeeper().closeTime(),
RCLTxSet{map});
1957 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->header().parentHash;
1959 for (
auto const& it : registry_.overlay().getActivePeers())
1961 if (it && (it->getClosedLedgerHash() == deadLedger))
1963 JLOG(m_journal.trace()) <<
"Killing obsolete peer status";
1969 bool ledgerChange = checkLastClosedLedger(registry_.overlay().getActivePeers(), networkClosed);
1971 if (networkClosed.
isZero())
1973 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
1983 if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::SYNCING)) && !ledgerChange)
1988 if (!needNetworkLedger_)
1989 setMode(OperatingMode::TRACKING);
1992 if (((mMode == OperatingMode::CONNECTED) || (mMode == OperatingMode::TRACKING)) && !ledgerChange)
1997 auto current = m_ledgerMaster.getCurrentLedger();
1998 if (registry_.timeKeeper().now() <
1999 (
current->header().parentCloseTime + 2 *
current->header().closeTimeResolution))
2001 setMode(OperatingMode::FULL);
2005 beginConsensus(networkClosed, clog);
2009NetworkOPsImp::consensusViewChange()
2011 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
2013 setMode(OperatingMode::CONNECTED);
2023 if (!mStreamMaps[sManifests].empty())
2027 jvObj[jss::type] =
"manifestReceived";
2033 jvObj[jss::signature] =
strHex(*sig);
2036 jvObj[jss::domain] = mo.
domain;
2039 for (
auto i = mStreamMaps[sManifests].begin(); i != mStreamMaps[sManifests].end();)
2041 if (
auto p = i->second.lock())
2043 p->send(jvObj,
true);
2048 i = mStreamMaps[sManifests].erase(i);
2054NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
2058 : loadFactorServer{loadFeeTrack.getLoadFactor()}
2059 , loadBaseServer{loadFeeTrack.getLoadBase()}
2061 , em{
std::move(escalationMetrics)}
2069 em.has_value() != b.
em.has_value())
2075 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2076 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel || em->referenceFeeLevel != b.
em->referenceFeeLevel);
2109 jvObj[jss::type] =
"serverStatus";
2111 jvObj[jss::load_base] = f.loadBaseServer;
2112 jvObj[jss::load_factor_server] = f.loadFactorServer;
2113 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
2118 safe_cast<std::uint64_t>(f.loadFactorServer),
2121 jvObj[jss::load_factor] =
trunc32(loadFactor);
2122 jvObj[jss::load_factor_fee_escalation] = f.em->openLedgerFeeLevel.jsonClipped();
2123 jvObj[jss::load_factor_fee_queue] = f.em->minProcessingFeeLevel.jsonClipped();
2124 jvObj[jss::load_factor_fee_reference] = f.em->referenceFeeLevel.jsonClipped();
2127 jvObj[jss::load_factor] = f.loadFactorServer;
2140 p->send(jvObj,
true);
2157 if (!streamMap.empty())
2160 jvObj[jss::type] =
"consensusPhase";
2161 jvObj[jss::consensus] =
to_string(phase);
2163 for (
auto i = streamMap.begin(); i != streamMap.end();)
2165 if (
auto p = i->second.lock())
2167 p->send(jvObj,
true);
2172 i = streamMap.erase(i);
2188 auto const signerPublic = val->getSignerPublic();
2190 jvObj[jss::type] =
"validationReceived";
2192 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2193 jvObj[jss::signature] =
strHex(val->getSignature());
2194 jvObj[jss::full] = val->isFull();
2195 jvObj[jss::flags] = val->getFlags();
2196 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2197 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2200 if (
auto version = (*val)[~sfServerVersion])
2203 if (
auto cookie = (*val)[~sfCookie])
2206 if (
auto hash = (*val)[~sfValidatedHash])
2207 jvObj[jss::validated_hash] =
strHex(*hash);
2211 if (masterKey != signerPublic)
2216 if (
auto const seq = (*val)[~sfLedgerSequence])
2217 jvObj[jss::ledger_index] = *seq;
2219 if (val->isFieldPresent(sfAmendments))
2222 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2223 jvObj[jss::amendments].append(
to_string(amendment));
2226 if (
auto const closeTime = (*val)[~sfCloseTime])
2227 jvObj[jss::close_time] = *closeTime;
2229 if (
auto const loadFee = (*val)[~sfLoadFee])
2230 jvObj[jss::load_fee] = *loadFee;
2232 if (
auto const baseFee = val->at(~sfBaseFee))
2233 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2235 if (
auto const reserveBase = val->at(~sfReserveBase))
2236 jvObj[jss::reserve_base] = *reserveBase;
2238 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2239 jvObj[jss::reserve_inc] = *reserveInc;
2243 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops); baseFeeXRP && baseFeeXRP->native())
2244 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2246 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops); reserveBaseXRP && reserveBaseXRP->native())
2247 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2249 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops); reserveIncXRP && reserveIncXRP->native())
2250 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2259 if (jvTx.
isMember(jss::ledger_index))
2261 jvTx[jss::ledger_index] =
std::to_string(jvTx[jss::ledger_index].asUInt());
2267 if (
auto p = i->second.lock())
2271 [&](
Json::Value const& jv) { p->send(jv,
true); });
2291 jvObj[jss::type] =
"peerStatusChange";
2299 p->send(jvObj,
true);
2313 using namespace std::chrono_literals;
2342 JLOG(
m_journal.
trace()) <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2357 JLOG(
m_journal.
warn()) <<
"Exception thrown for handling new validation " << val->getLedgerHash() <<
": "
2362 JLOG(
m_journal.
warn()) <<
"Unknown exception thrown for handling new validation " << val->getLedgerHash();
2374 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2411 "This server is amendment blocked, and must be updated to be "
2412 "able to stay in sync with the network.";
2419 "This server has an expired validator list. validators.txt "
2420 "may be incorrectly configured or some [validator_list_sites] "
2421 "may be unreachable.";
2428 "One or more unsupported amendments have reached majority. "
2429 "Upgrade to the latest version before they are activated "
2430 "to avoid being amendment blocked.";
2434 d[jss::expected_date] = expected->time_since_epoch().count();
2435 d[jss::expected_date_UTC] =
to_string(*expected);
2439 if (warnings.size())
2440 info[jss::warnings] = std::move(warnings);
2458 info[jss::network_ledger] =
"waiting";
2467 info[jss::node_size] =
"tiny";
2470 info[jss::node_size] =
"small";
2473 info[jss::node_size] =
"medium";
2476 info[jss::node_size] =
"large";
2479 info[jss::node_size] =
"huge";
2488 info[jss::validator_list_expires] = safe_cast<Json::UInt>(when->time_since_epoch().count());
2490 info[jss::validator_list_expires] = 0;
2500 if (*when == TimeKeeper::time_point::max())
2502 x[jss::expiration] =
"never";
2503 x[jss::status] =
"active";
2510 x[jss::status] =
"active";
2512 x[jss::status] =
"expired";
2517 x[jss::status] =
"unknown";
2518 x[jss::expiration] =
"unknown";
2522#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH)
2525#ifdef GIT_COMMIT_HASH
2526 x[jss::hash] = GIT_COMMIT_HASH;
2529 x[jss::branch] = GIT_BRANCH;
2545 info[jss::pubkey_validator] =
"none";
2555 info[jss::counters][jss::nodestore] = nodestore;
2564 info[jss::amendment_blocked] =
true;
2585 info[jss::last_close] = lastClose;
2593 info[jss::network_id] =
static_cast<Json::UInt>(*netid);
2602 auto const loadFactorFeeEscalation =
2603 mulDiv(escalationMetrics.openLedgerFeeLevel, loadBaseServer, escalationMetrics.referenceFeeLevel)
2606 auto const loadFactor =
std::max(safe_cast<std::uint64_t>(loadFactorServer), loadFactorFeeEscalation);
2610 info[jss::load_base] = loadBaseServer;
2611 info[jss::load_factor] =
trunc32(loadFactor);
2612 info[jss::load_factor_server] = loadFactorServer;
2619 info[jss::load_factor_fee_escalation] = escalationMetrics.openLedgerFeeLevel.jsonClipped();
2620 info[jss::load_factor_fee_queue] = escalationMetrics.minProcessingFeeLevel.jsonClipped();
2621 info[jss::load_factor_fee_reference] = escalationMetrics.referenceFeeLevel.jsonClipped();
2625 info[jss::load_factor] =
static_cast<double>(loadFactor) / loadBaseServer;
2627 if (loadFactorServer != loadFactor)
2628 info[jss::load_factor_server] =
static_cast<double>(loadFactorServer) / loadBaseServer;
2633 if (fee != loadBaseServer)
2634 info[jss::load_factor_local] =
static_cast<double>(fee) / loadBaseServer;
2636 if (fee != loadBaseServer)
2637 info[jss::load_factor_net] =
static_cast<double>(fee) / loadBaseServer;
2639 if (fee != loadBaseServer)
2640 info[jss::load_factor_cluster] =
static_cast<double>(fee) / loadBaseServer;
2642 if (escalationMetrics.openLedgerFeeLevel != escalationMetrics.referenceFeeLevel &&
2643 (admin || loadFactorFeeEscalation != loadFactor))
2644 info[jss::load_factor_fee_escalation] =
2645 escalationMetrics.openLedgerFeeLevel.decimalFromReference(escalationMetrics.referenceFeeLevel);
2646 if (escalationMetrics.minProcessingFeeLevel != escalationMetrics.referenceFeeLevel)
2647 info[jss::load_factor_fee_queue] =
2648 escalationMetrics.minProcessingFeeLevel.decimalFromReference(escalationMetrics.referenceFeeLevel);
2661 XRPAmount const baseFee = lpClosed->fees().base;
2663 l[jss::seq] =
Json::UInt(lpClosed->header().seq);
2664 l[jss::hash] =
to_string(lpClosed->header().hash);
2669 l[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
2670 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
2671 l[jss::close_time] =
Json::Value::UInt(lpClosed->header().closeTime.time_since_epoch().count());
2676 l[jss::reserve_base_xrp] = lpClosed->fees().reserve.decimalXRP();
2677 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
2680 l[jss::close_time_offset] =
static_cast<std::uint32_t>(closeOffset.count());
2686 l[jss::age] =
Json::UInt(age < highAgeThreshold ? age.count() : 0);
2690 auto lCloseTime = lpClosed->header().closeTime;
2692 if (lCloseTime <= closeTime)
2694 using namespace std::chrono_literals;
2695 auto age = closeTime - lCloseTime;
2696 l[jss::age] =
Json::UInt(age < highAgeThreshold ? age.count() : 0);
2702 info[jss::validated_ledger] = l;
2704 info[jss::closed_ledger] = l;
2708 info[jss::published_ledger] =
"none";
2709 else if (lpPublished->header().seq != lpClosed->header().seq)
2710 info[jss::published_ledger] = lpPublished->header().seq;
2728 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() && port.admin_user.empty() &&
2729 port.admin_password.empty()))
2743 for (
auto const& p : proto)
2744 jv[jss::protocol].append(p);
2751 auto const optPort = grpcSection.
get(
"port");
2752 if (optPort && grpcSection.get(
"ip"))
2755 jv[jss::port] = *optPort;
2757 jv[jss::protocol].
append(
"grpc");
2760 info[jss::ports] = std::move(ports);
2805 [&](
Json::Value const& jv) { p->send(jv, true); });
2831 XRPL_ASSERT(alpAccepted->getLedger().
get() == lpAccepted.
get(),
"xrpl::NetworkOPsImp::pubLedger : accepted input");
2834 JLOG(
m_journal.
debug()) <<
"Publishing ledger " << lpAccepted->header().seq <<
" " << lpAccepted->header().hash;
2842 jvObj[jss::type] =
"ledgerClosed";
2843 jvObj[jss::ledger_index] = lpAccepted->header().seq;
2844 jvObj[jss::ledger_hash] =
to_string(lpAccepted->header().hash);
2845 jvObj[jss::ledger_time] =
Json::Value::UInt(lpAccepted->header().closeTime.time_since_epoch().count());
2849 if (!lpAccepted->rules().enabled(featureXRPFees))
2851 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
2852 jvObj[jss::reserve_base] = lpAccepted->fees().reserve.jsonClipped();
2853 jvObj[jss::reserve_inc] = lpAccepted->fees().increment.jsonClipped();
2855 jvObj[jss::txn_count] =
Json::UInt(alpAccepted->size());
2868 p->send(jvObj,
true);
2886 p->send(jvObj,
true);
2895 static bool firstTime =
true;
2902 for (
auto& inner : outer.second)
2904 auto& subInfo = inner.second;
2905 if (subInfo.index_->separationLedgerSeq_ == 0)
2916 for (
auto const& accTx : *alpAccepted)
2971 jvObj[jss::type] =
"transaction";
2986 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
2987 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
2989 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
2991 if (transaction->isFieldPresent(sfNetworkID))
2992 netID = transaction->getFieldU32(sfNetworkID);
2995 jvObj[jss::ctid] = *ctid;
2997 if (!ledger->open())
2998 jvObj[jss::ledger_hash] =
to_string(ledger->header().hash);
3002 jvObj[jss::ledger_index] = ledger->header().seq;
3003 jvObj[jss::transaction][jss::date] = ledger->header().closeTime.time_since_epoch().count();
3004 jvObj[jss::validated] =
true;
3005 jvObj[jss::close_time_iso] =
to_string_iso(ledger->header().closeTime);
3011 jvObj[jss::validated] =
false;
3012 jvObj[jss::ledger_current_index] = ledger->header().seq;
3015 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3016 jvObj[jss::engine_result] = sToken;
3017 jvObj[jss::engine_result_code] = result;
3018 jvObj[jss::engine_result_message] = sHuman;
3020 if (transaction->getTxnType() == ttOFFER_CREATE)
3022 auto const account = transaction->getAccountID(sfAccount);
3023 auto const amount = transaction->getFieldAmount(sfTakerGets);
3026 if (account != amount.issue().account)
3029 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3038 RPC::insertDeliverMax(jvTx[jss::transaction], transaction->getTxnType(), Version);
3040 if constexpr (Version > 1)
3042 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3043 jvTx[jss::hash] = hash;
3047 jvTx[jss::transaction][jss::hash] = hash;
3060 auto const& stTxn = transaction.
getTxn();
3064 auto const trResult = transaction.
getResult();
3079 [&](
Json::Value const& jv) { p->send(jv, true); });
3096 [&](
Json::Value const& jv) { p->send(jv, true); });
3121 auto const currLedgerSeq = ledger->seq();
3127 for (
auto const& affectedAccount : transaction.
getAffected())
3131 auto it = simiIt->second.begin();
3133 while (it != simiIt->second.end())
3144 it = simiIt->second.erase(it);
3150 auto it = simiIt->second.begin();
3151 while (it != simiIt->second.end())
3162 it = simiIt->second.erase(it);
3168 auto& subs = historyIt->second;
3169 auto it = subs.begin();
3170 while (it != subs.end())
3173 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
3186 it = subs.erase(it);
3197 <<
"proposed=" << iProposed <<
", accepted=" << iAccepted;
3199 if (!notify.
empty() || !accountHistoryNotify.
empty())
3201 auto const& stTxn = transaction.
getTxn();
3205 auto const trResult = transaction.
getResult();
3211 isrListener->getApiVersion(),
3212 [&](
Json::Value const& jv) { isrListener->send(jv,
true); });
3216 jvObj.
set(jss::account_history_boundary,
true);
3220 "xrpl::NetworkOPsImp::pubAccountTransaction : "
3221 "account_history_tx_stream not set");
3222 for (
auto& info : accountHistoryNotify)
3224 auto& index = info.index_;
3225 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3226 jvObj.
set(jss::account_history_tx_first,
true);
3228 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3231 info.sink_->getApiVersion(),
3232 [&](
Json::Value const& jv) { info.sink_->send(jv,
true); });
3256 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3260 auto it = simiIt->second.begin();
3262 while (it != simiIt->second.end())
3273 it = simiIt->second.erase(it);
3280 JLOG(
m_journal.
trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3282 if (!notify.
empty() || !accountHistoryNotify.
empty())
3289 isrListener->getApiVersion(),
3290 [&](
Json::Value const& jv) { isrListener->send(jv,
true); });
3294 "xrpl::NetworkOPs::pubProposedAccountTransaction : "
3295 "account_history_tx_stream not set");
3296 for (
auto& info : accountHistoryNotify)
3298 auto& index = info.index_;
3299 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3300 jvObj.
set(jss::account_history_tx_first,
true);
3301 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3303 info.sink_->getApiVersion(),
3304 [&](
Json::Value const& jv) { info.sink_->send(jv,
true); });
3318 for (
auto const& naAccountID : vnaAccountIDs)
3322 isrListener->insertSubAccountInfo(naAccountID, rt);
3327 for (
auto const& naAccountID : vnaAccountIDs)
3329 auto simIterator = subMap.
find(naAccountID);
3330 if (simIterator == subMap.
end())
3334 usisElement[isrListener->getSeq()] = isrListener;
3336 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3341 simIterator->second[isrListener->getSeq()] = isrListener;
3349 for (
auto const& naAccountID : vnaAccountIDs)
3352 isrListener->deleteSubAccountInfo(naAccountID, rt);
3366 for (
auto const& naAccountID : vnaAccountIDs)
3368 auto simIterator = subMap.
find(naAccountID);
3370 if (simIterator != subMap.
end())
3373 simIterator->second.erase(uSeq);
3375 if (simIterator->second.empty())
3378 subMap.
erase(simIterator);
3387 enum DatabaseType { Sqlite,
None };
3388 static auto const databaseType = [&]() -> DatabaseType {
3393 return DatabaseType::Sqlite;
3395 return DatabaseType::None;
3398 if (databaseType == DatabaseType::None)
3401 UNREACHABLE(
"xrpl::NetworkOPsImp::addAccountHistoryJob : no database");
3414 auto const& accountId = subInfo.
index_->accountId_;
3415 auto& lastLedgerSeq = subInfo.
index_->historyLastLedgerSeq_;
3416 auto& txHistoryIndex = subInfo.
index_->historyTxIndex_;
3419 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
3428 auto stx = tx->getSTransaction();
3429 if (stx->getAccountID(sfAccount) == accountId && stx->getSeqValue() == 1)
3433 for (
auto& node : meta->getNodes())
3435 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
3438 if (node.isFieldPresent(sfNewFields))
3440 if (
auto inner =
dynamic_cast<STObject const*
>(node.peekAtPField(sfNewFields)); inner)
3442 if (inner->isFieldPresent(sfAccount) && inner->getAccountID(sfAccount) == accountId)
3453 auto send = [&](
Json::Value const& jvObj,
bool unsubscribe) ->
bool {
3456 sptr->send(jvObj,
true);
3465 auto sendMultiApiJson = [&](
MultiApiJson const& jvObj,
bool unsubscribe) ->
bool {
3469 sptr->getApiVersion(),
3470 [&](
Json::Value const& jv) { sptr->send(jv,
true); });
3490 return db->newestAccountTxPage(options);
3495 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
3496 "getMoreTxns : invalid database type");
3506 while (lastLedgerSeq >= 2 && !subInfo.
index_->stopHistorical_)
3508 int feeChargeCount = 0;
3517 <<
" no InfoSub. Fee charged " << feeChargeCount <<
" times.";
3522 auto startLedgerSeq = (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
3524 <<
", working on ledger range [" << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3526 auto haveRange = [&]() ->
bool {
3529 auto haveSomeValidatedLedgers =
3532 return haveSomeValidatedLedgers && validatedMin <= startLedgerSeq && lastLedgerSeq <= validatedMax;
3538 <<
", incomplete ledger range [" << startLedgerSeq <<
"," << lastLedgerSeq
3545 while (!subInfo.
index_->stopHistorical_)
3547 auto dbResult = getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
3552 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
3553 "getMoreTxns failed");
3555 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" getMoreTxns failed.";
3561 auto const& txns = dbResult->first;
3562 marker = dbResult->second;
3563 size_t num_txns = txns.size();
3564 for (
size_t i = 0; i < num_txns; ++i)
3566 auto const& [tx, meta] = txns[i];
3571 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" empty tx or meta.";
3580 "xrpl::NetworkOPsImp::addAccountHistoryJob : "
3581 "getLedgerBySeq failed");
3583 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" no ledger.";
3593 "NetworkOPsImp::addAccountHistoryJob : "
3594 "getSTransaction failed");
3596 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" getSTransaction failed.";
3603 auto const trR = meta->getResultTER();
3606 jvTx.
set(jss::account_history_tx_index, txHistoryIndex--);
3607 if (i + 1 == num_txns || txns[i + 1].first->getLedger() != tx->getLedger())
3608 jvTx.
set(jss::account_history_boundary,
true);
3610 if (isFirstTx(tx, meta))
3612 jvTx.
set(jss::account_history_tx_first,
true);
3613 sendMultiApiJson(jvTx,
false);
3616 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" done, found last tx.";
3621 sendMultiApiJson(jvTx,
false);
3628 <<
" paging, marker=" << marker->ledgerSeq <<
":" << marker->txnSeq;
3636 if (!subInfo.
index_->stopHistorical_)
3638 lastLedgerSeq = startLedgerSeq - 1;
3639 if (lastLedgerSeq <= 1)
3642 <<
"AccountHistory job for account " <<
toBase58(accountId) <<
" done, reached genesis ledger.";
3653 subInfo.
index_->separationLedgerSeq_ = ledger->seq();
3654 auto const& accountId = subInfo.
index_->accountId_;
3656 if (!ledger->exists(accountKeylet))
3659 <<
", no need to add AccountHistory job.";
3664 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
3666 if (sleAcct->getFieldU32(sfSequence) == 1)
3669 <<
" does not have tx, no need to add AccountHistory job.";
3677 "xrpl::NetworkOPsImp::subAccountHistoryStart : failed to "
3678 "access genesis account");
3683 subInfo.
index_->historyLastLedgerSeq_ = ledger->seq();
3684 subInfo.
index_->haveHistorical_ =
true;
3686 JLOG(
m_journal.
debug()) <<
"subAccountHistoryStart, add AccountHistory job: accountId=" <<
toBase58(accountId)
3687 <<
", currentLedgerSeq=" << ledger->seq();
3695 if (!isrListener->insertSubAccountHistory(accountId))
3707 inner.
emplace(isrListener->getSeq(), ahi);
3712 simIterator->second.emplace(isrListener->getSeq(), ahi);
3725 JLOG(
m_journal.
debug()) <<
"subAccountHistory, no validated ledger yet, delay start";
3735 isrListener->deleteSubAccountHistory(account);
3746 auto& subInfoMap = simIterator->second;
3747 auto subInfoIter = subInfoMap.find(seq);
3748 if (subInfoIter != subInfoMap.end())
3750 subInfoIter->second.index_->stopHistorical_ =
true;
3755 simIterator->second.erase(seq);
3756 if (simIterator->second.empty())
3762 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
3770 listeners->addSubscriber(isrListener);
3774 UNREACHABLE(
"xrpl::NetworkOPsImp::subBook : null book listeners");
3784 listeners->removeSubscriber(uSeq);
3794 XRPL_ASSERT(
m_standalone,
"xrpl::NetworkOPsImp::acceptLedger : is standalone");
3797 Throw<std::runtime_error>(
"Operation only possible in STANDALONE mode.");
3812 jvResult[jss::ledger_index] = lpClosed->header().seq;
3813 jvResult[jss::ledger_hash] =
to_string(lpClosed->header().hash);
3814 jvResult[jss::ledger_time] =
Json::Value::UInt(lpClosed->header().closeTime.time_since_epoch().count());
3815 if (!lpClosed->rules().enabled(featureXRPFees))
3817 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
3818 jvResult[jss::reserve_base] = lpClosed->fees().reserve.jsonClipped();
3819 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
3885 jvResult[jss::random] =
to_string(uRandom);
3887 jvResult[jss::load_base] = feeTrack.getLoadBase();
3888 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
3889 jvResult[jss::hostid] =
getHostId(admin);
4026 if (map.find(pInfo->getSeq()) != map.end())
4033#ifndef USE_NEW_BOOK_PAGE
4044 unsigned int iLimit,
4053 uint256 uTipIndex = uBookBase;
4057 stream <<
"getBookPage:" << book;
4058 stream <<
"getBookPage: uBookBase=" << uBookBase;
4059 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4060 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4068 bool bDirectAdvance =
true;
4072 unsigned int uBookEntry;
4078 while (!bDone && iLimit-- > 0)
4082 bDirectAdvance =
false;
4086 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4090 sleOfferDir.
reset();
4099 uTipIndex = sleOfferDir->key();
4102 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4104 JLOG(
m_journal.
trace()) <<
"getBookPage: uTipIndex=" << uTipIndex;
4105 JLOG(
m_journal.
trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4115 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4116 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4117 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4119 bool firstOwnerOffer(
true);
4125 saOwnerFunds = saTakerGets;
4127 else if (bGlobalFreeze)
4135 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4136 if (umBalanceEntry != umBalance.
end())
4140 saOwnerFunds = umBalanceEntry->second;
4141 firstOwnerOffer =
false;
4150 if (saOwnerFunds < beast::zero)
4154 saOwnerFunds.
clear();
4162 STAmount saOwnerFundsLimit = saOwnerFunds;
4174 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4177 if (saOwnerFundsLimit >= saTakerGets)
4180 saTakerGetsFunded = saTakerGets;
4186 saTakerGetsFunded = saOwnerFundsLimit;
4188 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4190 .setJson(jvOffer[jss::taker_pays_funded]);
4197 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4201 jvOf[jss::quality] = saDirRate.
getText();
4203 if (firstOwnerOffer)
4204 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4211 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4213 bDirectAdvance =
true;
4217 JLOG(
m_journal.
trace()) <<
"getBookPage: offerIndex=" << offerIndex;
4237 unsigned int iLimit,
4245 MetaView lesActive(lpLedger,
tapNONE,
true);
4246 OrderBookIterator obIterator(lesActive, book);
4250 bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.
out.
account) || lesActive.isGlobalFrozen(book.
in.
account);
4252 while (iLimit-- > 0 && obIterator.nextOffer())
4257 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4258 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4259 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4260 STAmount saDirRate = obIterator.getCurrentRate();
4266 saOwnerFunds = saTakerGets;
4268 else if (bGlobalFreeze)
4276 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4278 if (umBalanceEntry != umBalance.
end())
4282 saOwnerFunds = umBalanceEntry->second;
4291 if (saOwnerFunds.isNegative())
4295 saOwnerFunds.zero();
4302 STAmount saTakerGetsFunded;
4303 STAmount saOwnerFundsLimit = saOwnerFunds;
4315 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4318 if (saOwnerFundsLimit >= saTakerGets)
4321 saTakerGetsFunded = saTakerGets;
4326 saTakerGetsFunded = saOwnerFundsLimit;
4328 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
4332 std::min(saTakerPays,
multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
4333 .setJson(jvOffer[jss::taker_pays_funded]);
4336 STAmount saOwnerPays = (
parityRate == offerRate)
4338 :
std::
min(saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4340 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4342 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
4346 jvOf[jss::quality] = saDirRate.
getText();
4385 ++counters_[
static_cast<std::size_t>(om)].transitions;
4388 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(now - processStart_).count();
4391 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
4400 auto [counters, mode, start, initialSync] = getCounterData();
4411 auto& state = obj[jss::state_accounting][
states_[i]];
4412 state[jss::transitions] =
std::to_string(counters[i].transitions);
4413 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
4417 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
4432 boost::asio::io_context& io_svc,
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.
TxMeta const & getMeta() const
boost::container::flat_set< AccountID > const & getAffected() const
std::shared_ptr< STTx const > const & getTxn() const
virtual std::optional< NetClock::time_point > firstUnsupportedExpected() const =0
virtual std::chrono::milliseconds getIOLatency()=0
virtual Config & config()=0
virtual std::optional< PublicKey const > getValidationPublicKey() const =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::uint32_t getLoadFee() const
NetClock::time_point getReportTime() const
PublicKey const & identity() const
std::string const & name() const
std::size_t size() const
The number of nodes in the cluster list.
std::string SERVER_DOMAIN
int RELAY_UNTRUSTED_VALIDATIONS
static constexpr std::uint32_t FEE_UNITS_DEPRECATED
virtual Json::Value getInfo()=0
virtual void clearFailures()=0
std::shared_ptr< InfoSub > pointer
A pool of threads to perform work.
bool addJob(JobType type, std::string const &name, JobHandler &&jobHandler)
Adds a job to the JobQueue.
Json::Value getJson(int c=0)
std::chrono::seconds getValidatedLedgerAge()
bool getValidatedRange(std::uint32_t &minVal, std::uint32_t &maxVal)
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
bool haveValidated()
Whether we have ever fully validated a ledger.
std::size_t getFetchPackCacheSize() const
std::shared_ptr< Ledger const > getClosedLedger()
std::string getCompleteLedgers()
std::shared_ptr< Ledger const > getValidatedLedger()
std::shared_ptr< ReadView const > getPublishedLedger()
std::shared_ptr< ReadView const > getCurrentLedger()
Manages the current fee schedule.
std::uint32_t getClusterFee() const
std::uint32_t getLocalFee() const
std::uint32_t getRemoteFee() const
std::uint32_t getLoadFactor() const
std::uint32_t getLoadBase() 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 json(Json::Value &obj) const
Output state counters in JSON format.
std::chrono::steady_clock::time_point const processStart_
static std::array< Json::StaticString const, 5 > const states_
CounterData getCounterData() const
std::uint64_t initialSyncUs_
std::array< Counters, 5 > counters_
void mode(OperatingMode om)
Record state transition.
std::chrono::steady_clock::time_point start_
Transaction with input flags and results to be applied in batches.
std::shared_ptr< Transaction > const transaction
TransactionStatus(std::shared_ptr< Transaction > t, bool a, bool l, FailHard f)
std::string getHostId(bool forAdmin)
void reportConsensusStateChange(ConsensusPhase phase)
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
void clearNeedNetworkLedger() override
ServerFeeSummary mLastFeeSummary
Json::Value getOwnerInfo(std::shared_ptr< ReadView const > lpLedger, AccountID const &account) override
DispatchState mDispatchState
std::size_t const minPeerCount_
static std::array< char const *, 5 > const states_
std::set< uint256 > pendingValidations_
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
MultiApiJson transJson(std::shared_ptr< STTx const > const &transaction, TER result, bool validated, std::shared_ptr< ReadView const > const &ledger, std::optional< std::reference_wrapper< TxMeta const > > meta)
bool unsubManifests(std::uint64_t uListener) override
void pubPeerStatus(std::function< Json::Value(void)> const &) override
void unsubAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
bool subManifests(InfoSub::ref ispListener) override
void stateAccounting(Json::Value &obj) override
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
SubInfoMapType mSubRTAccount
void subAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
void transactionBatch()
Apply transactions in batches.
bool unsubRTTransactions(std::uint64_t uListener) override
void getBookPage(std::shared_ptr< ReadView const > &lpLedger, Book const &, AccountID const &uTakerID, bool const bProof, unsigned int iLimit, Json::Value const &jvMarker, Json::Value &jvResult) override
bool processTrustedProposal(RCLCxPeerPos proposal) override
error_code_i subAccountHistory(InfoSub::ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
void pubValidation(std::shared_ptr< STValidation > const &val) override
bool subBook(InfoSub::ref ispListener, Book const &) override
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::ref) override
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
std::atomic< OperatingMode > mMode
void setMode(OperatingMode om) override
void setAmendmentBlocked() override
void pubConsensus(ConsensusPhase phase)
std::recursive_mutex mSubLock
bool isNeedNetworkLedger() override
DispatchState
Synchronization states for transaction batches.
std::atomic< bool > needNetworkLedger_
boost::asio::steady_timer heartbeatTimer_
bool subConsensus(InfoSub::ref ispListener) override
bool unsubBook(std::uint64_t uListener, Book const &) override
bool unsubLedger(std::uint64_t uListener) override
bool checkLastClosedLedger(Overlay::PeerSequence const &, uint256 &networkClosed)
void pubProposedAccountTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result)
void unsubAccountHistoryInternal(std::uint64_t seq, AccountID const &account, bool historyOnly) override
void pubValidatedTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
void switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
std::optional< PublicKey > const validatorPK_
std::atomic< bool > amendmentBlocked_
void clearAmendmentWarned() override
void updateLocalTx(ReadView const &view) override
void clearLedgerFetch() override
void apply(std::unique_lock< std::mutex > &batchLock)
Attempt to apply transactions and post-process based on the results.
InfoSub::pointer findRpcSub(std::string const &strUrl) override
bool isAmendmentBlocked() override
std::string strOperatingMode(OperatingMode const mode, bool const admin) const override
std::unique_ptr< LocalTxs > m_localTX
void setStandAlone() override
void setNeedNetworkLedger() override
bool subServer(InfoSub::ref ispListener, Json::Value &jvResult, bool admin) override
void setTimer(boost::asio::steady_timer &timer, std::chrono::milliseconds const &expiry_time, std::function< void()> onExpire, std::function< void()> onError)
bool unsubServer(std::uint64_t uListener) override
SubAccountHistoryMapType mSubAccountHistory
void processClusterTimer()
bool unsubConsensus(std::uint64_t uListener) override
std::condition_variable mCond
void pubManifest(Manifest const &) override
void consensusViewChange() override
ServiceRegistry & registry_
boost::asio::steady_timer accountHistoryTxTimer_
Json::Value getConsensusInfo() override
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
void setUNLBlocked() override
bool unsubValidations(std::uint64_t uListener) override
bool subPeerStatus(InfoSub::ref ispListener) override
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
ConsensusPhase mLastConsensusPhase
OperatingMode getOperatingMode() const override
std::optional< PublicKey > const validatorMasterPK_
void doTransactionSyncBatch(std::unique_lock< std::mutex > &lock, std::function< bool(std::unique_lock< std::mutex > const &)> retryCallback)
std::array< SubMapType, SubTypes::sLastEntry > mStreamMaps
std::vector< TransactionStatus > mTransactions
bool tryRemoveRpcSub(std::string const &strUrl) override
bool beginConsensus(uint256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
void processHeartbeatTimer()
void doTransactionSync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failType)
For transactions submitted directly by a client, apply batch of transactions and wait for this transa...
void submitTransaction(std::shared_ptr< STTx const > const &) override
void setAmendmentWarned() override
LedgerMaster & m_ledgerMaster
Json::Value getServerInfo(bool human, bool admin, bool counters) override
StateAccounting accounting_
bool subValidations(InfoSub::ref ispListener) override
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
bool subRTTransactions(InfoSub::ref ispListener) override
std::atomic< bool > unlBlocked_
bool unsubBookChanges(std::uint64_t uListener) override
void unsubAccountHistory(InfoSub::ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
void setStateTimer() override
Called to initially start our timers.
std::size_t getLocalTxCount() override
bool preProcessTransaction(std::shared_ptr< Transaction > &transaction)
void processTransaction(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, FailHard failType) override
Process transactions as they arrive from the network or which are submitted by clients.
bool unsubTransactions(std::uint64_t uListener) override
bool isAmendmentWarned() override
bool subTransactions(InfoSub::ref ispListener) override
std::mutex validationsMutex_
std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay) override
Accepts the current transaction tree, return the new ledger's sequence.
SubInfoMapType mSubAccount
void clearUNLBlocked() override
bool isUNLBlocked() override
void pubProposedTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result) override
std::atomic< bool > amendmentWarned_
boost::asio::steady_timer clusterTimer_
NetworkOPsImp(ServiceRegistry ®istry, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool start_valid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
bool unsubPeerStatus(std::uint64_t uListener) override
void reportFeeChange() override
void processTransactionSet(CanonicalTXSet const &set) override
Process a set of transactions synchronously, and ensuring that they are processed in one batch.
void mapComplete(std::shared_ptr< SHAMap > const &map, bool fromAcquire) override
bool subLedger(InfoSub::ref ispListener, Json::Value &jvResult) override
bool isBlocked() override
~NetworkOPsImp() override
Json::Value getLedgerFetchInfo() override
void unsubAccountInternal(std::uint64_t seq, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
bool subBookChanges(InfoSub::ref ispListener) override
Provides server functionality for clients.
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.
virtual void processTxn(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &alTx, MultiApiJson const &jvObj)=0
virtual BookListeners::pointer makeBookListeners(Book const &)=0
virtual BookListeners::pointer getBookListeners(Book const &)=0
virtual std::uint64_t getPeerDisconnect() const =0
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 getPeerDisconnectCharges() const =0
virtual std::uint64_t getJqTransOverflow() const =0
virtual std::size_t size() const =0
Returns the number of active peers.
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)
Json::Value getJson(bool full) const
std::chrono::milliseconds prevRoundTime() const
Get duration of the previous round.
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::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.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
Issue const & issue() const
std::string getText() const override
void setJson(Json::Value &) 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)
Service registry for dependency injection.
virtual perf::PerfLog & getPerfLog()=0
virtual JobQueue & getJobQueue()=0
virtual RelationalDatabase & getRelationalDatabase()=0
virtual AmendmentTable & getAmendmentTable()=0
virtual ValidatorList & validators()=0
virtual Overlay & overlay()=0
virtual NodeStore::Database & getNodeStore()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual ServerHandler & getServerHandler()=0
virtual OpenLedger & openLedger()=0
virtual Cluster & cluster()=0
virtual InboundLedgers & getInboundLedgers()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual TimeKeeper & timeKeeper()=0
virtual OrderBookDB & getOrderBookDB()=0
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
virtual ManifestCache & validatorManifests()=0
virtual beast::Journal journal(std::string const &name)=0
virtual Application & app()=0
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::optional< PublicKey > localPublicKey() const
This function returns the local validator public key or a std::nullopt.
std::size_t quorum() const
Get quorum value for current trusted key set.
std::optional< TimeKeeper::time_point > expires() const
Return the time when the validator list will expire.
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.
Json::Value jsonClipped() const
constexpr double decimalXRP() 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.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
void rngfill(void *const buffer, std::size_t const bytes, Generator &g)
std::string const & getVersionString()
Server version.
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Encodes ledger sequence, transaction index, and network ID into a CTID string.
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.
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Charge const feeMediumBurdenRPC
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Rate rate(Env &env, Account const &account, std::uint32_t const &seq)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::unique_ptr< FeeVote > make_FeeVote(FeeSetup const &setup, beast::Journal journal)
Create an instance of the FeeVote logic.
STAmount divide(STAmount const &amount, Rate const &rate)
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
bool isTerRetry(TER x) noexcept
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
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.
constexpr std::uint32_t tfInnerBatchTxn
std::string to_string(base_uint< Bits, Tag > const &a)
std::string strHex(FwdIt begin, FwdIt end)
Rules makeRulesGivenLedger(DigestAwareReadView const &ledger, Rules const ¤t)
std::uint64_t getQuality(uint256 const &uBase)
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
FeeSetup setup_FeeVote(Section const §ion)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=shSIMPLE_BALANCE)
Number root(Number f, unsigned d)
bool transResultInfo(TER code, std::string &token, std::string &text)
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.
STAmount multiply(STAmount const &amount, Rate const &rate)
static auto const genesisAccountId
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
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::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
std::unique_ptr< NetworkOPs > make_NetworkOPs(ServiceRegistry ®istry, NetworkOPs::clock_type &clock, bool standalone, std::size_t minPeerCount, bool start_valid, JobQueue &job_queue, LedgerMaster &ledgerMaster, ValidatorKeys const &validatorKeys, boost::asio::io_context &io_svc, beast::Journal journal, beast::insight::Collector::ptr const &collector)
@ current
This was a new validation and was added.
constexpr std::size_t maxPoppedTransactions
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
STAmount amountFromQuality(std::uint64_t rate)
bool isTefFailure(TER x) noexcept
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
auto constexpr muldiv_max
uint256 getQualityNext(uint256 const &uBase)
ConsensusPhase
Phases of consensus for a single ledger round.
send_if_pred< Predicate > send_if(std::shared_ptr< Message > const &m, Predicate const &f)
Helper function to aid in type deduction.
void forAllApiVersions(Fn const &fn, Args &&... args)
AccountID calcAccountID(PublicKey const &pk)
uint256 getBookBase(Book const &book)
Json::Value rpcError(error_code_i iError)
std::string to_string_iso(date::sys_time< Duration > tp)
std::unique_ptr< LocalTxs > make_LocalTxs()
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
bool isTelLocal(TER x) noexcept
@ ledgerMaster
ledger master data for signing
@ proposal
proposal for signing
bool isTesSuccess(TER x) noexcept
static std::uint32_t trunc32(std::uint64_t v)
static std::array< char const *, 5 > const stateNames
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.
OperatingMode
Specifies the mode under which the server believes it's operating.
@ TRACKING
convinced we agree with the network
@ DISCONNECTED
not ready to process requests
@ CONNECTED
convinced we are talking to the network
@ FULL
we have the ledger and can even validate
@ SYNCING
fallen slightly behind
std::shared_ptr< STTx const > sterilize(STTx const &stx)
Sterilize a transaction.
bool isTemMalformed(TER x) noexcept
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
@ warnRPC_AMENDMENT_BLOCKED
@ warnRPC_UNSUPPORTED_MAJORITY
@ warnRPC_EXPIRED_VALIDATOR_LIST
T set_intersection(T... args)
PublicKey masterKey
The master key associated with this manifest.
std::string serialized
The manifest in serialized form.
Blob getMasterSignature() const
Returns manifest master key signature.
std::string domain
The domain, if one was specified in the manifest; empty otherwise.
std::optional< Blob > getSignature() const
Returns manifest signature.
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
std::uint32_t sequence
The sequence number of this manifest.
Server fees published on server subscription.
std::optional< TxQ::Metrics > em
bool operator!=(ServerFeeSummary const &b) const
bool operator==(ServerFeeSummary const &b) const
std::uint32_t loadBaseServer
ServerFeeSummary()=default
std::uint32_t loadFactorServer
decltype(initialSyncUs_) initialSyncUs
decltype(counters_) counters
std::chrono::microseconds dur
std::uint64_t transitions
beast::insight::Gauge syncing_duration
beast::insight::Gauge tracking_duration
beast::insight::Gauge connected_duration
beast::insight::Gauge tracking_transitions
Stats(Handler const &handler, beast::insight::Collector::ptr const &collector)
beast::insight::Gauge connected_transitions
beast::insight::Gauge full_transitions
beast::insight::Gauge disconnected_duration
beast::insight::Gauge syncing_transitions
beast::insight::Gauge disconnected_transitions
beast::insight::Gauge full_duration
beast::insight::Hook hook
std::int32_t historyTxIndex_
AccountID const accountId_
std::uint32_t forwardTxIndex_
std::uint32_t separationLedgerSeq_
std::uint32_t historyLastLedgerSeq_
SubAccountHistoryIndex(AccountID const &accountId)
std::atomic< bool > stopHistorical_
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.
void set(char const *key, auto const &v)
IsMemberResult isMember(char const *key) const
Select all peers (except optional excluded) that are in our cluster.
Sends a message to all peers.
T time_since_epoch(T... args)