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/misc/AmendmentTable.h>
32#include <xrpld/app/misc/DeliverMax.h>
33#include <xrpld/app/misc/HashRouter.h>
34#include <xrpld/app/misc/LoadFeeTrack.h>
35#include <xrpld/app/misc/NetworkOPs.h>
36#include <xrpld/app/misc/Transaction.h>
37#include <xrpld/app/misc/TxQ.h>
38#include <xrpld/app/misc/ValidatorKeys.h>
39#include <xrpld/app/misc/ValidatorList.h>
40#include <xrpld/app/misc/detail/AccountTxPaging.h>
41#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
42#include <xrpld/app/tx/apply.h>
43#include <xrpld/consensus/Consensus.h>
44#include <xrpld/consensus/ConsensusParms.h>
45#include <xrpld/overlay/Cluster.h>
46#include <xrpld/overlay/Overlay.h>
47#include <xrpld/overlay/predicates.h>
48#include <xrpld/perflog/PerfLog.h>
49#include <xrpld/rpc/BookChanges.h>
50#include <xrpld/rpc/CTID.h>
51#include <xrpld/rpc/DeliveredAmount.h>
52#include <xrpld/rpc/MPTokenIssuanceID.h>
53#include <xrpld/rpc/ServerHandler.h>
55#include <xrpl/basics/UptimeClock.h>
56#include <xrpl/basics/mulDiv.h>
57#include <xrpl/basics/safe_cast.h>
58#include <xrpl/basics/scope.h>
59#include <xrpl/beast/utility/rngfill.h>
60#include <xrpl/crypto/RFC1751.h>
61#include <xrpl/crypto/csprng.h>
62#include <xrpl/protocol/BuildInfo.h>
63#include <xrpl/protocol/Feature.h>
64#include <xrpl/protocol/MultiApiJson.h>
65#include <xrpl/protocol/RPCErr.h>
66#include <xrpl/protocol/jss.h>
67#include <xrpl/resource/Fees.h>
68#include <xrpl/resource/ResourceManager.h>
70#include <boost/asio/ip/host_name.hpp>
71#include <boost/asio/steady_timer.hpp>
110 "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : "
153 std::chrono::steady_clock::time_point
start_ =
214 return !(*
this != b);
233 boost::asio::io_service& io_svc,
247 app_.logs().journal(
"FeeVote")),
250 app.getInboundTransactions(),
251 beast::get_abstract_clock<
std::chrono::steady_clock>(),
253 app_.logs().journal(
"LedgerConsensus"))
255 validatorKeys.keys ? validatorKeys.keys->publicKey
258 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
440 getServerInfo(
bool human,
bool admin,
bool counters)
override;
467 TER result)
override;
501 bool historyOnly)
override;
507 bool historyOnly)
override;
575 boost::system::error_code ec;
580 <<
"NetworkOPs: heartbeatTimer cancel error: "
589 <<
"NetworkOPs: clusterTimer cancel error: "
598 <<
"NetworkOPs: accountHistoryTxTimer cancel error: "
603 using namespace std::chrono_literals;
613 boost::asio::steady_timer& timer,
796 template <
class Handler>
798 Handler
const& handler,
800 :
hook(collector->make_hook(handler))
803 "Disconnected_duration"))
806 "Connected_duration"))
808 collector->make_gauge(
"State_Accounting",
"Syncing_duration"))
811 "Tracking_duration"))
813 collector->make_gauge(
"State_Accounting",
"Full_duration"))
816 "Disconnected_transitions"))
819 "Connected_transitions"))
822 "Syncing_transitions"))
825 "Tracking_transitions"))
827 collector->make_gauge(
"State_Accounting",
"Full_transitions"))
856 {
"disconnected",
"connected",
"syncing",
"tracking",
"full"}};
918 static std::string const hostname = boost::asio::ip::host_name();
925 static std::string const shroudedHostId = [
this]() {
931 return shroudedHostId;
946 boost::asio::steady_timer& timer,
953 [
this, onExpire, onError](boost::system::error_code
const& e) {
954 if ((e.value() == boost::system::errc::success) &&
955 (!m_job_queue.isStopped()))
960 if (e.value() != boost::system::errc::success &&
961 e.value() != boost::asio::error::operation_aborted)
964 JLOG(m_journal.error())
965 <<
"Timer got error '" << e.message()
966 <<
"'. Restarting timer.";
971 timer.expires_from_now(expiry_time);
972 timer.async_wait(std::move(*optionalCountedHandler));
977NetworkOPsImp::setHeartbeatTimer()
981 mConsensus.parms().ledgerGRANULARITY,
983 m_job_queue.addJob(jtNETOP_TIMER,
"NetOPs.heartbeat", [this]() {
984 processHeartbeatTimer();
987 [
this]() { setHeartbeatTimer(); });
991NetworkOPsImp::setClusterTimer()
993 using namespace std::chrono_literals;
1000 processClusterTimer();
1003 [
this]() { setClusterTimer(); });
1009 JLOG(m_journal.debug()) <<
"Scheduling AccountHistory job for account "
1011 using namespace std::chrono_literals;
1013 accountHistoryTxTimer_,
1015 [
this, subInfo]() { addAccountHistoryJob(subInfo); },
1016 [
this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
1020NetworkOPsImp::processHeartbeatTimer()
1023 "Heartbeat Timer", mConsensus.validating(), m_journal);
1031 std::size_t const numPeers = app_.overlay().size();
1034 if (numPeers < minPeerCount_)
1036 if (mMode != OperatingMode::DISCONNECTED)
1038 setMode(OperatingMode::DISCONNECTED);
1040 ss <<
"Node count (" << numPeers <<
") has fallen "
1041 <<
"below required minimum (" << minPeerCount_ <<
").";
1042 JLOG(m_journal.warn()) << ss.
str();
1043 CLOG(clog.
ss()) <<
"set mode to DISCONNECTED: " << ss.
str();
1048 <<
"already DISCONNECTED. too few peers (" << numPeers
1049 <<
"), need at least " << minPeerCount_;
1056 setHeartbeatTimer();
1061 if (mMode == OperatingMode::DISCONNECTED)
1063 setMode(OperatingMode::CONNECTED);
1064 JLOG(m_journal.info())
1065 <<
"Node count (" << numPeers <<
") is sufficient.";
1066 CLOG(clog.
ss()) <<
"setting mode to CONNECTED based on " << numPeers
1072 auto origMode = mMode.load();
1073 CLOG(clog.
ss()) <<
"mode: " << strOperatingMode(origMode,
true);
1074 if (mMode == OperatingMode::SYNCING)
1075 setMode(OperatingMode::SYNCING);
1076 else if (mMode == OperatingMode::CONNECTED)
1077 setMode(OperatingMode::CONNECTED);
1078 auto newMode = mMode.load();
1079 if (origMode != newMode)
1082 <<
", changing to " << strOperatingMode(newMode,
true);
1084 CLOG(clog.
ss()) <<
". ";
1087 mConsensus.timerEntry(app_.timeKeeper().closeTime(), clog.
ss());
1089 CLOG(clog.
ss()) <<
"consensus phase " << to_string(mLastConsensusPhase);
1091 if (mLastConsensusPhase != currPhase)
1093 reportConsensusStateChange(currPhase);
1094 mLastConsensusPhase = currPhase;
1095 CLOG(clog.
ss()) <<
" changed to " << to_string(mLastConsensusPhase);
1097 CLOG(clog.
ss()) <<
". ";
1099 setHeartbeatTimer();
1103NetworkOPsImp::processClusterTimer()
1105 if (app_.cluster().size() == 0)
1108 using namespace std::chrono_literals;
1110 bool const update = app_.cluster().update(
1111 app_.nodeIdentity().first,
1113 (m_ledgerMaster.getValidatedLedgerAge() <= 4min)
1114 ? app_.getFeeTrack().getLocalFee()
1116 app_.timeKeeper().now());
1120 JLOG(m_journal.debug()) <<
"Too soon to send cluster update";
1125 protocol::TMCluster cluster;
1126 app_.cluster().for_each([&cluster](
ClusterNode const& node) {
1127 protocol::TMClusterNode& n = *cluster.add_clusternodes();
1132 n.set_nodename(node.
name());
1136 for (
auto& item : gossip.
items)
1138 protocol::TMLoadSource& node = *cluster.add_loadsources();
1139 node.set_name(to_string(item.address));
1140 node.set_cost(item.balance);
1142 app_.overlay().foreach(
send_if(
1143 std::make_shared<Message>(cluster, protocol::mtCLUSTER),
1154 if (mode == OperatingMode::FULL && admin)
1156 auto const consensusMode = mConsensus.mode();
1157 if (consensusMode != ConsensusMode::wrongLedger)
1159 if (consensusMode == ConsensusMode::proposing)
1162 if (mConsensus.validating())
1163 return "validating";
1173 if (isNeedNetworkLedger())
1182 auto const txid = trans->getTransactionID();
1183 auto const flags = app_.getHashRouter().getFlags(txid);
1185 if ((flags & SF_BAD) != 0)
1187 JLOG(m_journal.warn()) <<
"Submitted transaction cached bad";
1194 app_.getHashRouter(),
1196 m_ledgerMaster.getValidatedRules(),
1199 if (validity != Validity::Valid)
1201 JLOG(m_journal.warn())
1202 <<
"Submitted transaction invalid: " << reason;
1208 JLOG(m_journal.warn())
1209 <<
"Exception checking transaction " << txid <<
": " << ex.
what();
1216 auto tx = std::make_shared<Transaction>(trans, reason, app_);
1218 m_job_queue.addJob(
jtTRANSACTION,
"submitTxn", [
this, tx]() {
1220 processTransaction(t,
false,
false, FailHard::no);
1225NetworkOPsImp::processTransaction(
1231 auto ev = m_job_queue.makeLoadEvent(
jtTXN_PROC,
"ProcessTXN");
1232 auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
1234 if ((newFlags & SF_BAD) != 0)
1237 JLOG(m_journal.warn()) << transaction->getID() <<
": cached bad!\n";
1238 transaction->setStatus(
INVALID);
1246 auto const view = m_ledgerMaster.getCurrentLedger();
1248 app_.getHashRouter(),
1249 *transaction->getSTransaction(),
1253 validity == Validity::Valid,
1254 "ripple::NetworkOPsImp::processTransaction : valid validity");
1257 if (validity == Validity::SigBad)
1259 JLOG(m_journal.info()) <<
"Transaction has bad signature: " << reason;
1260 transaction->setStatus(
INVALID);
1262 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
1267 app_.getMasterTransaction().canonicalize(&transaction);
1270 doTransactionSync(transaction, bUnlimited, failType);
1272 doTransactionAsync(transaction, bUnlimited, failType);
1276NetworkOPsImp::doTransactionAsync(
1283 if (transaction->getApplying())
1286 mTransactions.push_back(
1288 transaction->setApplying();
1290 if (mDispatchState == DispatchState::none)
1292 if (m_job_queue.addJob(
1293 jtBATCH,
"transactionBatch", [
this]() { transactionBatch(); }))
1295 mDispatchState = DispatchState::scheduled;
1301NetworkOPsImp::doTransactionSync(
1308 if (!transaction->getApplying())
1310 mTransactions.push_back(
1312 transaction->setApplying();
1317 if (mDispatchState == DispatchState::running)
1326 if (mTransactions.size())
1329 if (m_job_queue.addJob(
jtBATCH,
"transactionBatch", [
this]() {
1333 mDispatchState = DispatchState::scheduled;
1337 }
while (transaction->getApplying());
1341NetworkOPsImp::transactionBatch()
1345 if (mDispatchState == DispatchState::running)
1348 while (mTransactions.size())
1359 mTransactions.
swap(transactions);
1361 !transactions.
empty(),
1362 "ripple::NetworkOPsImp::apply : non-empty transactions");
1364 mDispatchState != DispatchState::running,
1365 "ripple::NetworkOPsImp::apply : is not running");
1367 mDispatchState = DispatchState::running;
1373 bool changed =
false;
1376 m_ledgerMaster.peekMutex(), std::defer_lock};
1387 if (e.failType == FailHard::yes)
1390 auto const result = app_.getTxQ().apply(
1391 app_, view, e.transaction->getSTransaction(), flags, j);
1392 e.result = result.ter;
1393 e.applied = result.applied;
1394 changed = changed || result.applied;
1403 if (
auto const l = m_ledgerMaster.getValidatedLedger())
1404 validatedLedgerIndex = l->info().seq;
1406 auto newOL = app_.openLedger().current();
1409 e.transaction->clearSubmitResult();
1413 pubProposedTransaction(
1414 newOL, e.transaction->getSTransaction(), e.result);
1415 e.transaction->setApplied();
1418 e.transaction->setResult(e.result);
1421 app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
1430 JLOG(m_journal.info())
1431 <<
"TransactionResult: " << token <<
": " << human;
1436 bool addLocal = e.local;
1440 JLOG(m_journal.debug())
1441 <<
"Transaction is now included in open ledger";
1442 e.transaction->setStatus(
INCLUDED);
1444 auto const& txCur = e.transaction->getSTransaction();
1445 auto const txNext = m_ledgerMaster.popAcctTransaction(txCur);
1450 auto t = std::make_shared<Transaction>(trans, reason, app_);
1451 submit_held.
emplace_back(t,
false,
false, FailHard::no);
1458 JLOG(m_journal.info()) <<
"Transaction is obsolete";
1459 e.transaction->setStatus(
OBSOLETE);
1463 JLOG(m_journal.debug())
1464 <<
"Transaction is likely to claim a"
1465 <<
" fee, but is queued until fee drops";
1467 e.transaction->setStatus(
HELD);
1471 m_ledgerMaster.addHeldTransaction(e.transaction);
1472 e.transaction->setQueued();
1473 e.transaction->setKept();
1477 if (e.failType != FailHard::yes)
1480 JLOG(m_journal.debug())
1481 <<
"Transaction should be held: " << e.result;
1482 e.transaction->setStatus(
HELD);
1483 m_ledgerMaster.addHeldTransaction(e.transaction);
1484 e.transaction->setKept();
1489 JLOG(m_journal.debug())
1490 <<
"Status other than success " << e.result;
1491 e.transaction->setStatus(
INVALID);
1494 auto const enforceFailHard =
1495 e.failType == FailHard::yes && !
isTesSuccess(e.result);
1497 if (addLocal && !enforceFailHard)
1499 m_localTX->push_back(
1500 m_ledgerMaster.getCurrentLedgerIndex(),
1501 e.transaction->getSTransaction());
1502 e.transaction->setKept();
1506 ((mMode != OperatingMode::FULL) &&
1507 (e.failType != FailHard::yes) && e.local) ||
1512 app_.getHashRouter().shouldRelay(e.transaction->getID());
1516 protocol::TMTransaction tx;
1519 e.transaction->getSTransaction()->add(s);
1520 tx.set_rawtransaction(s.
data(), s.
size());
1521 tx.set_status(protocol::tsCURRENT);
1522 tx.set_receivetimestamp(
1523 app_.timeKeeper().now().time_since_epoch().count());
1526 app_.overlay().relay(e.transaction->getID(), tx, *toSkip);
1527 e.transaction->setBroadcast();
1531 if (validatedLedgerIndex)
1533 auto [fee, accountSeq, availableSeq] =
1534 app_.getTxQ().getTxRequiredFeeAndSeq(
1535 *newOL, e.transaction->getSTransaction());
1536 e.transaction->setCurrentLedgerState(
1537 *validatedLedgerIndex, fee, accountSeq, availableSeq);
1545 e.transaction->clearApplying();
1547 if (!submit_held.
empty())
1549 if (mTransactions.empty())
1550 mTransactions.swap(submit_held);
1552 for (
auto& e : submit_held)
1553 mTransactions.push_back(std::move(e));
1558 mDispatchState = DispatchState::none;
1566NetworkOPsImp::getOwnerInfo(
1571 auto root = keylet::ownerDir(account);
1572 auto sleNode = lpLedger->read(keylet::page(
root));
1579 for (
auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
1581 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
1584 "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE");
1586 switch (sleCur->getType())
1589 if (!jvObjects.
isMember(jss::offers))
1590 jvObjects[jss::offers] =
1593 jvObjects[jss::offers].
append(
1594 sleCur->getJson(JsonOptions::none));
1597 case ltRIPPLE_STATE:
1598 if (!jvObjects.
isMember(jss::ripple_lines))
1600 jvObjects[jss::ripple_lines] =
1604 jvObjects[jss::ripple_lines].
append(
1605 sleCur->getJson(JsonOptions::none));
1608 case ltACCOUNT_ROOT:
1612 "ripple::NetworkOPsImp::getOwnerInfo : invalid "
1618 uNodeDir = sleNode->getFieldU64(sfIndexNext);
1622 sleNode = lpLedger->read(keylet::page(
root, uNodeDir));
1625 "ripple::NetworkOPsImp::getOwnerInfo : read next page");
1638NetworkOPsImp::isBlocked()
1640 return isAmendmentBlocked() || isUNLBlocked();
1644NetworkOPsImp::isAmendmentBlocked()
1646 return amendmentBlocked_;
1650NetworkOPsImp::setAmendmentBlocked()
1652 amendmentBlocked_ =
true;
1653 setMode(OperatingMode::CONNECTED);
1657NetworkOPsImp::isAmendmentWarned()
1659 return !amendmentBlocked_ && amendmentWarned_;
1663NetworkOPsImp::setAmendmentWarned()
1665 amendmentWarned_ =
true;
1669NetworkOPsImp::clearAmendmentWarned()
1671 amendmentWarned_ =
false;
1675NetworkOPsImp::isUNLBlocked()
1681NetworkOPsImp::setUNLBlocked()
1684 setMode(OperatingMode::CONNECTED);
1688NetworkOPsImp::clearUNLBlocked()
1690 unlBlocked_ =
false;
1694NetworkOPsImp::checkLastClosedLedger(
1703 JLOG(m_journal.trace()) <<
"NetworkOPsImp::checkLastClosedLedger";
1705 auto const ourClosed = m_ledgerMaster.getClosedLedger();
1710 uint256 closedLedger = ourClosed->info().hash;
1711 uint256 prevClosedLedger = ourClosed->info().parentHash;
1712 JLOG(m_journal.trace()) <<
"OurClosed: " << closedLedger;
1713 JLOG(m_journal.trace()) <<
"PrevClosed: " << prevClosedLedger;
1718 auto& validations = app_.getValidations();
1719 JLOG(m_journal.debug())
1720 <<
"ValidationTrie " <<
Json::Compact(validations.getJsonTrie());
1724 peerCounts[closedLedger] = 0;
1725 if (mMode >= OperatingMode::TRACKING)
1726 peerCounts[closedLedger]++;
1728 for (
auto& peer : peerList)
1730 uint256 peerLedger = peer->getClosedLedgerHash();
1733 ++peerCounts[peerLedger];
1736 for (
auto const& it : peerCounts)
1737 JLOG(m_journal.debug()) <<
"L: " << it.first <<
" n=" << it.second;
1739 uint256 preferredLCL = validations.getPreferredLCL(
1741 m_ledgerMaster.getValidLedgerIndex(),
1744 bool switchLedgers = preferredLCL != closedLedger;
1746 closedLedger = preferredLCL;
1748 if (switchLedgers && (closedLedger == prevClosedLedger))
1751 JLOG(m_journal.info()) <<
"We won't switch to our own previous ledger";
1752 networkClosed = ourClosed->info().hash;
1753 switchLedgers =
false;
1756 networkClosed = closedLedger;
1761 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
1764 consensus = app_.getInboundLedgers().acquire(
1765 closedLedger, 0, InboundLedger::Reason::CONSENSUS);
1768 (!m_ledgerMaster.canBeCurrent(consensus) ||
1769 !m_ledgerMaster.isCompatible(
1770 *consensus, m_journal.debug(),
"Not switching")))
1774 networkClosed = ourClosed->info().hash;
1778 JLOG(m_journal.warn()) <<
"We are not running on the consensus ledger";
1779 JLOG(m_journal.info()) <<
"Our LCL: " << ourClosed->info().hash
1781 JLOG(m_journal.info()) <<
"Net LCL " << closedLedger;
1783 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
1785 setMode(OperatingMode::CONNECTED);
1793 switchLastClosedLedger(consensus);
1800NetworkOPsImp::switchLastClosedLedger(
1804 JLOG(m_journal.error())
1805 <<
"JUMP last closed ledger to " << newLCL->info().hash;
1807 clearNeedNetworkLedger();
1810 app_.getTxQ().processClosedLedger(app_, *newLCL,
true);
1817 auto retries = m_localTX->getTxSet();
1818 auto const lastVal = app_.getLedgerMaster().getValidatedLedger();
1823 rules.
emplace(app_.config().features);
1824 app_.openLedger().accept(
1835 return app_.getTxQ().accept(app_, view);
1839 m_ledgerMaster.switchLCL(newLCL);
1841 protocol::TMStatusChange s;
1842 s.set_newevent(protocol::neSWITCHED_LEDGER);
1843 s.set_ledgerseq(newLCL->info().seq);
1844 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
1845 s.set_ledgerhashprevious(
1846 newLCL->info().parentHash.begin(), newLCL->info().parentHash.size());
1847 s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size());
1849 app_.overlay().foreach(
1850 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
1854NetworkOPsImp::beginConsensus(
1860 "ripple::NetworkOPsImp::beginConsensus : nonzero input");
1862 auto closingInfo = m_ledgerMaster.getCurrentLedger()->info();
1864 JLOG(m_journal.info()) <<
"Consensus time for #" << closingInfo.seq
1865 <<
" with LCL " << closingInfo.parentHash;
1867 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
1872 if (mMode == OperatingMode::FULL)
1874 JLOG(m_journal.warn()) <<
"Don't have LCL, going to tracking";
1875 setMode(OperatingMode::TRACKING);
1876 CLOG(clog) <<
"beginConsensus Don't have LCL, going to tracking. ";
1879 CLOG(clog) <<
"beginConsensus no previous ledger. ";
1884 prevLedger->info().hash == closingInfo.parentHash,
1885 "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches "
1888 closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash,
1889 "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches "
1892 if (prevLedger->rules().enabled(featureNegativeUNL))
1893 app_.validators().setNegativeUNL(prevLedger->negativeUNL());
1894 TrustChanges const changes = app_.validators().updateTrusted(
1895 app_.getValidations().getCurrentNodeIDs(),
1896 closingInfo.parentCloseTime,
1899 app_.getHashRouter());
1901 if (!changes.
added.empty() || !changes.
removed.empty())
1903 app_.getValidations().trustChanged(changes.
added, changes.
removed);
1905 app_.getAmendmentTable().trustChanged(
1906 app_.validators().getQuorumKeys().second);
1909 mConsensus.startRound(
1910 app_.timeKeeper().closeTime(),
1918 if (mLastConsensusPhase != currPhase)
1920 reportConsensusStateChange(currPhase);
1921 mLastConsensusPhase = currPhase;
1924 JLOG(m_journal.debug()) <<
"Initiating consensus engine";
1931 auto const& peerKey = peerPos.
publicKey();
1932 if (validatorPK_ == peerKey || validatorMasterPK_ == peerKey)
1943 JLOG(m_journal.error())
1944 <<
"Received a proposal signed by MY KEY from a peer. This may "
1945 "indicate a misconfiguration where another node has the same "
1946 "validator key, or may be caused by unusual message routing and "
1951 return mConsensus.peerProposal(app_.timeKeeper().closeTime(), peerPos);
1962 protocol::TMHaveTransactionSet msg;
1963 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
1964 msg.set_status(protocol::tsHAVE);
1965 app_.overlay().foreach(
1966 send_always(std::make_shared<Message>(msg, protocol::mtHAVE_SET)));
1970 mConsensus.gotTxSet(app_.timeKeeper().closeTime(),
RCLTxSet{map});
1976 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash;
1978 for (
auto const& it : app_.overlay().getActivePeers())
1980 if (it && (it->getClosedLedgerHash() == deadLedger))
1982 JLOG(m_journal.trace()) <<
"Killing obsolete peer status";
1989 checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed);
1991 if (networkClosed.
isZero())
1993 CLOG(clog) <<
"endConsensus last closed ledger is zero. ";
2003 if (((mMode == OperatingMode::CONNECTED) ||
2004 (mMode == OperatingMode::SYNCING)) &&
2010 if (!needNetworkLedger_)
2011 setMode(OperatingMode::TRACKING);
2014 if (((mMode == OperatingMode::CONNECTED) ||
2015 (mMode == OperatingMode::TRACKING)) &&
2021 auto current = m_ledgerMaster.getCurrentLedger();
2022 if (app_.timeKeeper().now() < (
current->info().parentCloseTime +
2023 2 *
current->info().closeTimeResolution))
2025 setMode(OperatingMode::FULL);
2029 beginConsensus(networkClosed, clog);
2033NetworkOPsImp::consensusViewChange()
2035 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
2037 setMode(OperatingMode::CONNECTED);
2047 if (!mStreamMaps[sManifests].empty())
2051 jvObj[jss::type] =
"manifestReceived";
2054 jvObj[jss::signing_key] =
2058 jvObj[jss::signature] =
strHex(*sig);
2061 jvObj[jss::domain] = mo.
domain;
2064 for (
auto i = mStreamMaps[sManifests].begin();
2065 i != mStreamMaps[sManifests].end();)
2067 if (
auto p = i->second.lock())
2069 p->send(jvObj,
true);
2074 i = mStreamMaps[sManifests].erase(i);
2080NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
2084 : loadFactorServer{loadFeeTrack.getLoadFactor()}
2085 , loadBaseServer{loadFeeTrack.getLoadBase()}
2087 , em{
std::move(escalationMetrics)}
2097 em.has_value() != b.
em.has_value())
2103 em->minProcessingFeeLevel != b.
em->minProcessingFeeLevel ||
2104 em->openLedgerFeeLevel != b.
em->openLedgerFeeLevel ||
2105 em->referenceFeeLevel != b.
em->referenceFeeLevel);
2138 jvObj[jss::type] =
"serverStatus";
2140 jvObj[jss::load_base] = f.loadBaseServer;
2141 jvObj[jss::load_factor_server] = f.loadFactorServer;
2142 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
2147 safe_cast<std::uint64_t>(f.loadFactorServer),
2149 f.em->openLedgerFeeLevel,
2151 f.em->referenceFeeLevel)
2154 jvObj[jss::load_factor] =
trunc32(loadFactor);
2155 jvObj[jss::load_factor_fee_escalation] =
2156 f.em->openLedgerFeeLevel.jsonClipped();
2157 jvObj[jss::load_factor_fee_queue] =
2158 f.em->minProcessingFeeLevel.jsonClipped();
2159 jvObj[jss::load_factor_fee_reference] =
2160 f.em->referenceFeeLevel.jsonClipped();
2163 jvObj[jss::load_factor] = f.loadFactorServer;
2177 p->send(jvObj,
true);
2194 if (!streamMap.empty())
2197 jvObj[jss::type] =
"consensusPhase";
2198 jvObj[jss::consensus] =
to_string(phase);
2200 for (
auto i = streamMap.begin(); i != streamMap.end();)
2202 if (
auto p = i->second.lock())
2204 p->send(jvObj,
true);
2209 i = streamMap.erase(i);
2225 auto const signerPublic = val->getSignerPublic();
2227 jvObj[jss::type] =
"validationReceived";
2228 jvObj[jss::validation_public_key] =
2230 jvObj[jss::ledger_hash] =
to_string(val->getLedgerHash());
2231 jvObj[jss::signature] =
strHex(val->getSignature());
2232 jvObj[jss::full] = val->isFull();
2233 jvObj[jss::flags] = val->getFlags();
2234 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
2235 jvObj[jss::data] =
strHex(val->getSerializer().slice());
2237 if (
auto version = (*val)[~sfServerVersion])
2240 if (
auto cookie = (*val)[~sfCookie])
2243 if (
auto hash = (*val)[~sfValidatedHash])
2244 jvObj[jss::validated_hash] =
strHex(*hash);
2246 auto const masterKey =
2249 if (masterKey != signerPublic)
2254 if (
auto const seq = (*val)[~sfLedgerSequence])
2255 jvObj[jss::ledger_index] = *seq;
2257 if (val->isFieldPresent(sfAmendments))
2260 for (
auto const& amendment : val->getFieldV256(sfAmendments))
2264 if (
auto const closeTime = (*val)[~sfCloseTime])
2265 jvObj[jss::close_time] = *closeTime;
2267 if (
auto const loadFee = (*val)[~sfLoadFee])
2268 jvObj[jss::load_fee] = *loadFee;
2270 if (
auto const baseFee = val->at(~sfBaseFee))
2271 jvObj[jss::base_fee] =
static_cast<double>(*baseFee);
2273 if (
auto const reserveBase = val->at(~sfReserveBase))
2274 jvObj[jss::reserve_base] = *reserveBase;
2276 if (
auto const reserveInc = val->at(~sfReserveIncrement))
2277 jvObj[jss::reserve_inc] = *reserveInc;
2281 if (
auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops);
2282 baseFeeXRP && baseFeeXRP->native())
2283 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
2285 if (
auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
2286 reserveBaseXRP && reserveBaseXRP->native())
2287 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
2289 if (
auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
2290 reserveIncXRP && reserveIncXRP->native())
2291 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
2300 if (jvTx.
isMember(jss::ledger_index))
2302 jvTx[jss::ledger_index] =
2303 std::to_string(jvTx[jss::ledger_index].asUInt());
2310 if (
auto p = i->second.lock())
2314 [&](
Json::Value const& jv) { p->send(jv, true); });
2334 jvObj[jss::type] =
"peerStatusChange";
2343 p->send(jvObj,
true);
2357 using namespace std::chrono_literals;
2389 <<
"recvValidation " << val->getLedgerHash() <<
" from " << source;
2405 <<
"Exception thrown for handling new validation "
2406 << val->getLedgerHash() <<
": " << e.
what();
2411 <<
"Unknown exception thrown for handling new validation "
2412 << val->getLedgerHash();
2424 ss <<
"VALIDATION: " << val->render() <<
" master_key: ";
2461 "This server is amendment blocked, and must be updated to be "
2462 "able to stay in sync with the network.";
2469 "This server has an expired validator list. validators.txt "
2470 "may be incorrectly configured or some [validator_list_sites] "
2471 "may be unreachable.";
2478 "One or more unsupported amendments have reached majority. "
2479 "Upgrade to the latest version before they are activated "
2480 "to avoid being amendment blocked.";
2481 if (
auto const expected =
2485 d[jss::expected_date] = expected->time_since_epoch().count();
2486 d[jss::expected_date_UTC] =
to_string(*expected);
2490 if (warnings.size())
2491 info[jss::warnings] = std::move(warnings);
2506 info[jss::time] =
to_string(std::chrono::floor<std::chrono::microseconds>(
2510 info[jss::network_ledger] =
"waiting";
2512 info[jss::validation_quorum] =
2520 info[jss::node_size] =
"tiny";
2523 info[jss::node_size] =
"small";
2526 info[jss::node_size] =
"medium";
2529 info[jss::node_size] =
"large";
2532 info[jss::node_size] =
"huge";
2541 info[jss::validator_list_expires] =
2542 safe_cast<Json::UInt>(when->time_since_epoch().count());
2544 info[jss::validator_list_expires] = 0;
2554 if (*when == TimeKeeper::time_point::max())
2556 x[jss::expiration] =
"never";
2557 x[jss::status] =
"active";
2564 x[jss::status] =
"active";
2566 x[jss::status] =
"expired";
2571 x[jss::status] =
"unknown";
2572 x[jss::expiration] =
"unknown";
2576#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH)
2579#ifdef GIT_COMMIT_HASH
2580 x[jss::hash] = GIT_COMMIT_HASH;
2583 x[jss::branch] = GIT_BRANCH;
2588 info[jss::io_latency_ms] =
2596 info[jss::pubkey_validator] =
2601 info[jss::pubkey_validator] =
"none";
2611 info[jss::counters][jss::nodestore] = nodestore;
2615 info[jss::pubkey_node] =
2621 info[jss::amendment_blocked] =
true;
2635 lastClose[jss::converge_time_s] =
2640 lastClose[jss::converge_time] =
2644 info[jss::last_close] = lastClose;
2652 info[jss::network_id] =
static_cast<Json::UInt>(*netid);
2654 auto const escalationMetrics =
2662 auto const loadFactorFeeEscalation =
2664 escalationMetrics.openLedgerFeeLevel,
2666 escalationMetrics.referenceFeeLevel)
2670 safe_cast<std::uint64_t>(loadFactorServer), loadFactorFeeEscalation);
2674 info[jss::load_base] = loadBaseServer;
2675 info[jss::load_factor] =
trunc32(loadFactor);
2676 info[jss::load_factor_server] = loadFactorServer;
2683 info[jss::load_factor_fee_escalation] =
2684 escalationMetrics.openLedgerFeeLevel.jsonClipped();
2685 info[jss::load_factor_fee_queue] =
2686 escalationMetrics.minProcessingFeeLevel.jsonClipped();
2687 info[jss::load_factor_fee_reference] =
2688 escalationMetrics.referenceFeeLevel.jsonClipped();
2692 info[jss::load_factor] =
2693 static_cast<double>(loadFactor) / loadBaseServer;
2695 if (loadFactorServer != loadFactor)
2696 info[jss::load_factor_server] =
2697 static_cast<double>(loadFactorServer) / loadBaseServer;
2702 if (fee != loadBaseServer)
2703 info[jss::load_factor_local] =
2704 static_cast<double>(fee) / loadBaseServer;
2706 if (fee != loadBaseServer)
2707 info[jss::load_factor_net] =
2708 static_cast<double>(fee) / loadBaseServer;
2710 if (fee != loadBaseServer)
2711 info[jss::load_factor_cluster] =
2712 static_cast<double>(fee) / loadBaseServer;
2714 if (escalationMetrics.openLedgerFeeLevel !=
2715 escalationMetrics.referenceFeeLevel &&
2716 (admin || loadFactorFeeEscalation != loadFactor))
2717 info[jss::load_factor_fee_escalation] =
2718 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
2719 escalationMetrics.referenceFeeLevel);
2720 if (escalationMetrics.minProcessingFeeLevel !=
2721 escalationMetrics.referenceFeeLevel)
2722 info[jss::load_factor_fee_queue] =
2723 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
2724 escalationMetrics.referenceFeeLevel);
2737 XRPAmount const baseFee = lpClosed->fees().base;
2739 l[jss::seq] =
Json::UInt(lpClosed->info().seq);
2740 l[jss::hash] =
to_string(lpClosed->info().hash);
2745 l[jss::reserve_base] =
2746 lpClosed->fees().accountReserve(0).jsonClipped();
2747 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
2749 lpClosed->info().closeTime.time_since_epoch().count());
2754 l[jss::reserve_base_xrp] =
2755 lpClosed->fees().accountReserve(0).decimalXRP();
2756 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
2759 std::abs(closeOffset.count()) >= 60)
2760 l[jss::close_time_offset] =
2768 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2772 auto lCloseTime = lpClosed->info().closeTime;
2774 if (lCloseTime <= closeTime)
2776 using namespace std::chrono_literals;
2777 auto age = closeTime - lCloseTime;
2779 Json::UInt(age < highAgeThreshold ? age.count() : 0);
2785 info[jss::validated_ledger] = l;
2787 info[jss::closed_ledger] = l;
2791 info[jss::published_ledger] =
"none";
2792 else if (lpPublished->info().seq != lpClosed->info().seq)
2793 info[jss::published_ledger] = lpPublished->info().seq;
2798 info[jss::jq_trans_overflow] =
2800 info[jss::peer_disconnects] =
2802 info[jss::peer_disconnects_resources] =
2807 "http",
"https",
"peer",
"ws",
"ws2",
"wss",
"wss2"};
2815 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
2816 port.admin_user.empty() && port.admin_password.empty()))
2830 for (
auto const& p : proto)
2831 jv[jss::protocol].append(p);
2838 auto const optPort = grpcSection.
get(
"port");
2839 if (optPort && grpcSection.get(
"ip"))
2842 jv[jss::port] = *optPort;
2844 jv[jss::protocol].append(
"grpc");
2847 info[jss::ports] = std::move(ports);
2872 transJson(transaction, result,
false, ledger, std::nullopt);
2886 [&](
Json::Value const& jv) { p->send(jv, true); });
2909 alpAccepted = std::make_shared<AcceptedLedger>(lpAccepted,
app_);
2911 lpAccepted->info().hash, alpAccepted);
2915 alpAccepted->getLedger().
get() == lpAccepted.
get(),
2916 "ripple::NetworkOPsImp::pubLedger : accepted input");
2920 <<
"Publishing ledger " << lpAccepted->info().seq <<
" "
2921 << lpAccepted->info().hash;
2929 jvObj[jss::type] =
"ledgerClosed";
2930 jvObj[jss::ledger_index] = lpAccepted->info().seq;
2931 jvObj[jss::ledger_hash] =
to_string(lpAccepted->info().hash);
2933 lpAccepted->info().closeTime.time_since_epoch().count());
2935 if (!lpAccepted->rules().enabled(featureXRPFees))
2937 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
2938 jvObj[jss::reserve_base] =
2939 lpAccepted->fees().accountReserve(0).jsonClipped();
2940 jvObj[jss::reserve_inc] =
2941 lpAccepted->fees().increment.jsonClipped();
2943 jvObj[jss::txn_count] =
Json::UInt(alpAccepted->size());
2947 jvObj[jss::validated_ledgers] =
2957 p->send(jvObj,
true);
2975 p->send(jvObj,
true);
2984 static bool firstTime =
true;
2991 for (
auto& inner : outer.second)
2993 auto& subInfo = inner.second;
2994 if (subInfo.index_->separationLedgerSeq_ == 0)
2997 alpAccepted->getLedger(), subInfo);
3006 for (
auto const& accTx : *alpAccepted)
3010 lpAccepted, *accTx, accTx == *(--alpAccepted->end()));
3037 "reportConsensusStateChange->pubConsensus",
3068 jvObj[jss::type] =
"transaction";
3072 jvObj[jss::transaction] =
3079 jvObj[jss::meta], *ledger, transaction, meta->
get());
3081 jvObj[jss::meta], transaction, meta->
get());
3085 if (
auto const& lookup = ledger->txRead(transaction->getTransactionID());
3086 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
3088 uint32_t
const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
3090 if (transaction->isFieldPresent(sfNetworkID))
3091 netID = transaction->getFieldU32(sfNetworkID);
3096 jvObj[jss::ctid] = *ctid;
3098 if (!ledger->open())
3099 jvObj[jss::ledger_hash] =
to_string(ledger->info().hash);
3103 jvObj[jss::ledger_index] = ledger->info().seq;
3104 jvObj[jss::transaction][jss::date] =
3105 ledger->info().closeTime.time_since_epoch().count();
3106 jvObj[jss::validated] =
true;
3107 jvObj[jss::close_time_iso] =
to_string_iso(ledger->info().closeTime);
3113 jvObj[jss::validated] =
false;
3114 jvObj[jss::ledger_current_index] = ledger->info().seq;
3117 jvObj[jss::status] = validated ?
"closed" :
"proposed";
3118 jvObj[jss::engine_result] = sToken;
3119 jvObj[jss::engine_result_code] = result;
3120 jvObj[jss::engine_result_message] = sHuman;
3122 if (transaction->getTxnType() == ttOFFER_CREATE)
3124 auto const account = transaction->getAccountID(sfAccount);
3125 auto const amount = transaction->getFieldAmount(sfTakerGets);
3128 if (account != amount.issue().account)
3136 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
3144 [&]<
unsigned Version>(
3146 RPC::insertDeliverMax(
3147 jvTx[jss::transaction], transaction->getTxnType(), Version);
3149 if constexpr (Version > 1)
3151 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
3152 jvTx[jss::hash] = hash;
3156 jvTx[jss::transaction][jss::hash] = hash;
3169 auto const& stTxn = transaction.
getTxn();
3173 auto const trResult = transaction.
getResult();
3188 [&](
Json::Value const& jv) { p->send(jv, true); });
3205 [&](
Json::Value const& jv) { p->send(jv, true); });
3230 auto const currLedgerSeq = ledger->seq();
3237 for (
auto const& affectedAccount : transaction.
getAffected())
3242 auto it = simiIt->second.begin();
3244 while (it != simiIt->second.end())
3255 it = simiIt->second.erase(it);
3262 auto it = simiIt->second.begin();
3263 while (it != simiIt->second.end())
3274 it = simiIt->second.erase(it);
3281 auto& subs = histoIt->second;
3282 auto it = subs.begin();
3283 while (it != subs.end())
3286 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
3300 it = subs.erase(it);
3311 <<
"pubAccountTransaction: " <<
"proposed=" << iProposed
3312 <<
", accepted=" << iAccepted;
3314 if (!notify.
empty() || !accountHistoryNotify.
empty())
3316 auto const& stTxn = transaction.
getTxn();
3320 auto const trResult = transaction.
getResult();
3326 isrListener->getApiVersion(),
3327 [&](
Json::Value const& jv) { isrListener->send(jv, true); });
3331 jvObj.
set(jss::account_history_boundary,
true);
3334 jvObj.
isMember(jss::account_history_tx_stream) ==
3336 "ripple::NetworkOPsImp::pubAccountTransaction : "
3337 "account_history_tx_stream not set");
3338 for (
auto& info : accountHistoryNotify)
3340 auto& index = info.index_;
3341 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3342 jvObj.
set(jss::account_history_tx_first,
true);
3344 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3347 info.sink_->getApiVersion(),
3348 [&](
Json::Value const& jv) { info.sink_->send(jv, true); });
3373 for (
auto const& affectedAccount : tx->getMentionedAccounts())
3378 auto it = simiIt->second.begin();
3380 while (it != simiIt->second.end())
3391 it = simiIt->second.erase(it);
3398 JLOG(
m_journal.
trace()) <<
"pubProposedAccountTransaction: " << iProposed;
3400 if (!notify.
empty() || !accountHistoryNotify.
empty())
3407 isrListener->getApiVersion(),
3408 [&](
Json::Value const& jv) { isrListener->send(jv, true); });
3411 jvObj.
isMember(jss::account_history_tx_stream) ==
3413 "ripple::NetworkOPs::pubProposedAccountTransaction : "
3414 "account_history_tx_stream not set");
3415 for (
auto& info : accountHistoryNotify)
3417 auto& index = info.index_;
3418 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
3419 jvObj.
set(jss::account_history_tx_first,
true);
3420 jvObj.
set(jss::account_history_tx_index, index->forwardTxIndex_++);
3422 info.sink_->getApiVersion(),
3423 [&](
Json::Value const& jv) { info.sink_->send(jv, true); });
3440 for (
auto const& naAccountID : vnaAccountIDs)
3443 <<
"subAccount: account: " <<
toBase58(naAccountID);
3445 isrListener->insertSubAccountInfo(naAccountID, rt);
3450 for (
auto const& naAccountID : vnaAccountIDs)
3452 auto simIterator = subMap.
find(naAccountID);
3453 if (simIterator == subMap.
end())
3457 usisElement[isrListener->getSeq()] = isrListener;
3459 subMap.
insert(simIterator, make_pair(naAccountID, usisElement));
3464 simIterator->second[isrListener->getSeq()] = isrListener;
3475 for (
auto const& naAccountID : vnaAccountIDs)
3478 isrListener->deleteSubAccountInfo(naAccountID, rt);
3495 for (
auto const& naAccountID : vnaAccountIDs)
3497 auto simIterator = subMap.
find(naAccountID);
3499 if (simIterator != subMap.
end())
3502 simIterator->second.erase(uSeq);
3504 if (simIterator->second.empty())
3507 subMap.
erase(simIterator);
3516 enum DatabaseType { Sqlite,
None };
3517 static const auto databaseType = [&]() -> DatabaseType {
3522 return DatabaseType::Sqlite;
3524 return DatabaseType::None;
3527 if (databaseType == DatabaseType::None)
3530 <<
"AccountHistory job for account "
3542 "AccountHistoryTxStream",
3543 [
this, dbType = databaseType, subInfo]() {
3544 auto const& accountId = subInfo.
index_->accountId_;
3545 auto& lastLedgerSeq = subInfo.
index_->historyLastLedgerSeq_;
3546 auto& txHistoryIndex = subInfo.
index_->historyTxIndex_;
3549 <<
"AccountHistory job for account " <<
toBase58(accountId)
3550 <<
" started. lastLedgerSeq=" << lastLedgerSeq;
3560 auto stx = tx->getSTransaction();
3561 if (stx->getAccountID(sfAccount) == accountId &&
3562 stx->getSeqProxy().value() == 1)
3566 for (
auto& node : meta->getNodes())
3568 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
3571 if (node.isFieldPresent(sfNewFields))
3573 if (
auto inner =
dynamic_cast<const STObject*
>(
3574 node.peekAtPField(sfNewFields));
3577 if (inner->isFieldPresent(sfAccount) &&
3578 inner->getAccountID(sfAccount) == accountId)
3590 bool unsubscribe) ->
bool {
3593 sptr->send(jvObj,
true);
3603 bool unsubscribe) ->
bool {
3607 sptr->getApiVersion(),
3608 [&](
Json::Value const& jv) { sptr->send(jv,
true); });
3631 accountId, minLedger, maxLedger, marker, 0,
true};
3632 return db->newestAccountTxPage(options);
3636 "ripple::NetworkOPsImp::addAccountHistoryJob::"
3637 "getMoreTxns : invalid database type");
3646 while (lastLedgerSeq >= 2 && !subInfo.
index_->stopHistorical_)
3648 int feeChargeCount = 0;
3657 <<
"AccountHistory job for account "
3658 <<
toBase58(accountId) <<
" no InfoSub. Fee charged "
3659 << feeChargeCount <<
" times.";
3664 auto startLedgerSeq =
3665 (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
3667 <<
"AccountHistory job for account " <<
toBase58(accountId)
3668 <<
", working on ledger range [" << startLedgerSeq <<
","
3669 << lastLedgerSeq <<
"]";
3671 auto haveRange = [&]() ->
bool {
3674 auto haveSomeValidatedLedgers =
3676 validatedMin, validatedMax);
3678 return haveSomeValidatedLedgers &&
3679 validatedMin <= startLedgerSeq &&
3680 lastLedgerSeq <= validatedMax;
3686 <<
"AccountHistory reschedule job for account "
3687 <<
toBase58(accountId) <<
", incomplete ledger range ["
3688 << startLedgerSeq <<
"," << lastLedgerSeq <<
"]";
3694 while (!subInfo.
index_->stopHistorical_)
3697 getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
3701 <<
"AccountHistory job for account "
3702 <<
toBase58(accountId) <<
" getMoreTxns failed.";
3707 auto const& txns = dbResult->first;
3708 marker = dbResult->second;
3709 size_t num_txns = txns.size();
3710 for (
size_t i = 0; i < num_txns; ++i)
3712 auto const& [tx, meta] = txns[i];
3717 <<
"AccountHistory job for account "
3718 <<
toBase58(accountId) <<
" empty tx or meta.";
3728 <<
"AccountHistory job for account "
3729 <<
toBase58(accountId) <<
" no ledger.";
3734 tx->getSTransaction();
3738 <<
"AccountHistory job for account "
3740 <<
" getSTransaction failed.";
3746 auto const trR = meta->getResultTER();
3748 transJson(stTxn, trR,
true, curTxLedger, mRef);
3751 jss::account_history_tx_index, txHistoryIndex--);
3752 if (i + 1 == num_txns ||
3753 txns[i + 1].first->getLedger() != tx->getLedger())
3754 jvTx.
set(jss::account_history_boundary,
true);
3756 if (isFirstTx(tx, meta))
3758 jvTx.
set(jss::account_history_tx_first,
true);
3759 sendMultiApiJson(jvTx,
false);
3762 <<
"AccountHistory job for account "
3764 <<
" done, found last tx.";
3769 sendMultiApiJson(jvTx,
false);
3776 <<
"AccountHistory job for account "
3778 <<
" paging, marker=" << marker->ledgerSeq <<
":"
3787 if (!subInfo.
index_->stopHistorical_)
3789 lastLedgerSeq = startLedgerSeq - 1;
3790 if (lastLedgerSeq <= 1)
3793 <<
"AccountHistory job for account "
3795 <<
" done, reached genesis ledger.";
3808 subInfo.
index_->separationLedgerSeq_ = ledger->seq();
3809 auto const& accountId = subInfo.
index_->accountId_;
3811 if (!ledger->exists(accountKeylet))
3814 <<
"subAccountHistoryStart, no account " <<
toBase58(accountId)
3815 <<
", no need to add AccountHistory job.";
3820 if (
auto const sleAcct = ledger->read(accountKeylet); sleAcct)
3822 if (sleAcct->getFieldU32(sfSequence) == 1)
3825 <<
"subAccountHistoryStart, genesis account "
3827 <<
" does not have tx, no need to add AccountHistory job.";
3834 "ripple::NetworkOPsImp::subAccountHistoryStart : failed to "
3835 "access genesis account");
3839 subInfo.
index_->historyLastLedgerSeq_ = ledger->seq();
3840 subInfo.
index_->haveHistorical_ =
true;
3843 <<
"subAccountHistoryStart, add AccountHistory job: accountId="
3844 <<
toBase58(accountId) <<
", currentLedgerSeq=" << ledger->seq();
3854 if (!isrListener->insertSubAccountHistory(accountId))
3857 <<
"subAccountHistory, already subscribed to account "
3864 isrListener, std::make_shared<SubAccountHistoryIndex>(accountId)};
3869 inner.
emplace(isrListener->getSeq(), ahi);
3875 simIterator->second.emplace(isrListener->getSeq(), ahi);
3889 <<
"subAccountHistory, no validated ledger yet, delay start";
3902 isrListener->deleteSubAccountHistory(account);
3916 auto& subInfoMap = simIterator->second;
3917 auto subInfoIter = subInfoMap.find(seq);
3918 if (subInfoIter != subInfoMap.end())
3920 subInfoIter->second.index_->stopHistorical_ =
true;
3925 simIterator->second.erase(seq);
3926 if (simIterator->second.empty())
3932 <<
"unsubAccountHistory, account " <<
toBase58(account)
3933 <<
", historyOnly = " << (historyOnly ?
"true" :
"false");
3941 listeners->addSubscriber(isrListener);
3943 UNREACHABLE(
"ripple::NetworkOPsImp::subBook : null book listeners");
3951 listeners->removeSubscriber(uSeq);
3963 m_standalone,
"ripple::NetworkOPsImp::acceptLedger : is standalone");
3966 Throw<std::runtime_error>(
3967 "Operation only possible in STANDALONE mode.");
3982 jvResult[jss::ledger_index] = lpClosed->info().seq;
3983 jvResult[jss::ledger_hash] =
to_string(lpClosed->info().hash);
3985 lpClosed->info().closeTime.time_since_epoch().count());
3986 if (!lpClosed->rules().enabled(featureXRPFees))
3988 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
3989 jvResult[jss::reserve_base] =
3990 lpClosed->fees().accountReserve(0).jsonClipped();
3991 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
3996 jvResult[jss::validated_ledgers] =
4002 .emplace(isrListener->getSeq(), isrListener)
4012 .emplace(isrListener->getSeq(), isrListener)
4038 .emplace(isrListener->getSeq(), isrListener)
4066 jvResult[jss::random] =
to_string(uRandom);
4068 jvResult[jss::load_base] = feeTrack.getLoadBase();
4069 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
4070 jvResult[jss::hostid] =
getHostId(admin);
4071 jvResult[jss::pubkey_node] =
4076 .emplace(isrListener->getSeq(), isrListener)
4094 .emplace(isrListener->getSeq(), isrListener)
4112 .emplace(isrListener->getSeq(), isrListener)
4130 .emplace(isrListener->getSeq(), isrListener)
4154 .emplace(isrListener->getSeq(), isrListener)
4172 .emplace(isrListener->getSeq(), isrListener)
4220 if (map.find(pInfo->getSeq()) != map.end())
4227#ifndef USE_NEW_BOOK_PAGE
4238 unsigned int iLimit,
4248 uint256 uTipIndex = uBookBase;
4252 stream <<
"getBookPage:" << book;
4253 stream <<
"getBookPage: uBookBase=" << uBookBase;
4254 stream <<
"getBookPage: uBookEnd=" << uBookEnd;
4255 stream <<
"getBookPage: uTipIndex=" << uTipIndex;
4264 bool bDirectAdvance =
true;
4268 unsigned int uBookEntry;
4274 while (!bDone && iLimit-- > 0)
4278 bDirectAdvance =
false;
4282 auto const ledgerIndex = view.
succ(uTipIndex, uBookEnd);
4286 sleOfferDir.
reset();
4295 uTipIndex = sleOfferDir->key();
4298 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
4301 <<
"getBookPage: uTipIndex=" << uTipIndex;
4303 <<
"getBookPage: offerIndex=" << offerIndex;
4313 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4314 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4315 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4317 bool firstOwnerOffer(
true);
4323 saOwnerFunds = saTakerGets;
4325 else if (bGlobalFreeze)
4333 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4334 if (umBalanceEntry != umBalance.
end())
4338 saOwnerFunds = umBalanceEntry->second;
4339 firstOwnerOffer =
false;
4353 if (saOwnerFunds < beast::zero)
4357 saOwnerFunds.
clear();
4365 STAmount saOwnerFundsLimit = saOwnerFunds;
4377 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4380 if (saOwnerFundsLimit >= saTakerGets)
4383 saTakerGetsFunded = saTakerGets;
4389 saTakerGetsFunded = saOwnerFundsLimit;
4391 saTakerGetsFunded.
setJson(jvOffer[jss::taker_gets_funded]);
4395 saTakerGetsFunded, saDirRate, saTakerPays.
issue()))
4396 .setJson(jvOffer[jss::taker_pays_funded]);
4402 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4404 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4408 jvOf[jss::quality] = saDirRate.
getText();
4410 if (firstOwnerOffer)
4411 jvOf[jss::owner_funds] = saOwnerFunds.
getText();
4418 if (!
cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
4420 bDirectAdvance =
true;
4425 <<
"getBookPage: offerIndex=" << offerIndex;
4445 unsigned int iLimit,
4453 MetaView lesActive(lpLedger,
tapNONE,
true);
4454 OrderBookIterator obIterator(lesActive, book);
4458 const bool bGlobalFreeze = lesActive.isGlobalFrozen(book.
out.
account) ||
4459 lesActive.isGlobalFrozen(book.
in.
account);
4461 while (iLimit-- > 0 && obIterator.nextOffer())
4466 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
4467 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
4468 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
4469 STAmount saDirRate = obIterator.getCurrentRate();
4475 saOwnerFunds = saTakerGets;
4477 else if (bGlobalFreeze)
4485 auto umBalanceEntry = umBalance.
find(uOfferOwnerID);
4487 if (umBalanceEntry != umBalance.
end())
4491 saOwnerFunds = umBalanceEntry->second;
4497 saOwnerFunds = lesActive.accountHolds(
4503 if (saOwnerFunds.isNegative())
4507 saOwnerFunds.zero();
4514 STAmount saTakerGetsFunded;
4515 STAmount saOwnerFundsLimit = saOwnerFunds;
4527 saOwnerFundsLimit =
divide(saOwnerFunds, offerRate);
4530 if (saOwnerFundsLimit >= saTakerGets)
4533 saTakerGetsFunded = saTakerGets;
4538 saTakerGetsFunded = saOwnerFundsLimit;
4540 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
4546 multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
4547 .setJson(jvOffer[jss::taker_pays_funded]);
4550 STAmount saOwnerPays = (
parityRate == offerRate)
4553 saOwnerFunds,
multiply(saTakerGetsFunded, offerRate));
4555 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
4557 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
4561 jvOf[jss::quality] = saDirRate.
getText();
4576 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4616 ++counters_[
static_cast<std::size_t>(om)].transitions;
4618 counters_[
static_cast<std::size_t>(om)].transitions == 1)
4620 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(
4621 now - processStart_)
4625 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
4634 auto [counters, mode, start, initialSync] = getCounterData();
4635 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
4645 auto& state = obj[jss::state_accounting][
states_[i]];
4646 state[jss::transitions] =
std::to_string(counters[i].transitions);
4647 state[jss::duration_us] =
std::to_string(counters[i].dur.count());
4651 obj[jss::initial_sync_duration_us] =
std::to_string(initialSync);
4666 boost::asio::io_service& io_svc,
4670 return std::make_unique<NetworkOPsImp>(
T back_inserter(T... args)
Decorator for streaming out compact json.
Lightweight wrapper to tag static string.
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Value & append(const Value &value)
Append value to array at the end.
bool isMember(const char *key) const
Return true if the object has a member named key.
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
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
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 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
void getBookPage(std::shared_ptr< ReadView const > &lpLedger, Book const &, AccountID const &uTakerID, const bool bProof, unsigned int iLimit, Json::Value const &jvMarker, Json::Value &jvResult) override
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
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 clearNeedNetworkLedger() override
DispatchState mDispatchState
bool subBookChanges(InfoSub::ref ispListener) override
SubInfoMapType mSubRTAccount
bool checkLastClosedLedger(const Overlay::PeerSequence &, uint256 &networkClosed)
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 &)
BookListeners::pointer makeBookListeners(Book const &)
void processTxn(std::shared_ptr< ReadView const > const &ledger, const AcceptedLedgerTx &alTx, MultiApiJson const &jvObj)
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.
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
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.
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.
void set(const char *key, auto const &v)
IsMemberResult isMember(const char *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)