mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
Five signals that explain why a node is not advancing toward full, none of
which were observable before:
- state_changes_total now carries {from,to} mode labels, emitted at
setMode using the existing strOperatingMode helper. A bare count could
not distinguish a healthy climb from a node flapping between tracking
and connected. Removes the now-unused incrementStateChanges wrapper.
- sync_state{initial_full_duration_us}: time to first reach full, which
StateAccounting already computed but exposed only in server_info.
- sync_state{network_ledger_gate}: whether the node is still refusing to
build ledgers because it has no network ledger.
- sync_state{server_stall_seconds} and server_stall_events_total: how
long the main thread has been unresponsive. LoadManager computed this
and only logged it, so a stall was invisible until the fatal threshold.
The episode rule is a pure function so it can be tested without adding
a test-only mutator to LoadManager.
- sync_state{ledgers_behind}: how far our validated sequence trails the
best sequence any peer advertises, read from already-cached peer ranges
so no extra network traffic is added.
Also fixes the naming checker: it derived only the first label of a
multi-label instrument, so a dashboard querying the second label was
wrongly rejected.
Note: the clang-tidy hook cannot run in this worktree (no build
directory); the remaining pre-commit hooks, the naming check, dashboard
schema and harness syntax all pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
316 lines
9.9 KiB
C++
316 lines
9.9 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/basics/base_uint.h>
|
|
#include <xrpl/beast/clock/abstract_clock.h>
|
|
#include <xrpl/core/ServiceRegistry.h>
|
|
#include <xrpl/json/json_value.h>
|
|
#include <xrpl/protocol/AccountID.h>
|
|
#include <xrpl/protocol/Book.h>
|
|
#include <xrpl/protocol/STValidation.h>
|
|
#include <xrpl/protocol/TER.h>
|
|
#include <xrpl/server/InfoSub.h>
|
|
|
|
#include <boost/asio.hpp>
|
|
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace xrpl {
|
|
|
|
// Operations that clients may wish to perform against the network
|
|
// Master operational handler, server sequencer, network tracker
|
|
|
|
class Peer;
|
|
class STTx;
|
|
class ReadView;
|
|
class LedgerMaster;
|
|
class Transaction;
|
|
class ValidatorKeys;
|
|
class CanonicalTXSet;
|
|
class RCLCxPeerPos;
|
|
class SHAMap;
|
|
|
|
// This is the primary interface into the "client" portion of the program.
|
|
// Code that wants to do normal operations on the network such as
|
|
// creating and monitoring accounts, creating transactions, and so on
|
|
// should use this interface. The RPC code will primarily be a light wrapper
|
|
// over this code.
|
|
//
|
|
// Eventually, it will check the node's operating mode (synced, unsynced,
|
|
// etcetera) and defer to the correct means of processing. The current
|
|
// code assumes this node is synced (and will continue to do so until
|
|
// there's a functional network.
|
|
//
|
|
|
|
/**
|
|
* Specifies the mode under which the server believes it's operating.
|
|
*
|
|
* This has implications about how the server processes transactions and
|
|
* how it responds to requests (e.g. account balance request).
|
|
*
|
|
* @note Other code relies on the numerical values of these constants; do
|
|
* not change them without verifying each use and ensuring that it is
|
|
* not a breaking change.
|
|
*/
|
|
enum class OperatingMode {
|
|
DISCONNECTED = 0, ///< not ready to process requests
|
|
CONNECTED = 1, ///< convinced we are talking to the network
|
|
SYNCING = 2, ///< fallen slightly behind
|
|
TRACKING = 3, ///< convinced we agree with the network
|
|
FULL = 4 ///< we have the ledger and can even validate
|
|
};
|
|
|
|
/**
|
|
* Provides server functionality for clients.
|
|
*
|
|
* Clients include backend applications, local commands, and connected
|
|
* clients. This class acts as a proxy, fulfilling the command with local
|
|
* data if possible, or asking the network and returning the results if
|
|
* needed.
|
|
*
|
|
* A backend application or local client can trust a local instance of
|
|
* xrpld / NetworkOPs. However, client software connecting to non-local
|
|
* instances of xrpld will need to be hardened to protect against hostile
|
|
* or unreliable servers.
|
|
*/
|
|
class NetworkOPs : public InfoSub::Source
|
|
{
|
|
public:
|
|
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
|
|
|
|
enum class FailHard : unsigned char { No, Yes };
|
|
static FailHard
|
|
doFailHard(bool noMeansDont)
|
|
{
|
|
return noMeansDont ? FailHard::Yes : FailHard::No;
|
|
}
|
|
|
|
public:
|
|
~NetworkOPs() override = default;
|
|
|
|
virtual void
|
|
stop() = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Network information
|
|
//
|
|
|
|
[[nodiscard]] virtual OperatingMode
|
|
getOperatingMode() const = 0;
|
|
/**
|
|
* Time spent in the current operating mode so far, in microseconds.
|
|
* Same value as `server_state_duration_us` in server_info; exposed as a
|
|
* lightweight accessor so metrics can read it without building the full
|
|
* server_info JSON on every collection tick.
|
|
*/
|
|
[[nodiscard]] virtual std::chrono::microseconds
|
|
getServerStateDurationUs() const = 0;
|
|
/**
|
|
* Microseconds from process start until the node first reached FULL.
|
|
*
|
|
* Zero while the node has not completed initial sync yet, so a value that
|
|
* stays at zero is itself the signal that sync never finished. Once set it
|
|
* never changes: this is the one-shot time-to-first-FULL, not the time in
|
|
* the current state. Same value as `initial_sync_duration_us` in
|
|
* server_info, exposed as a lightweight accessor so metrics can read it
|
|
* without building the full server_info JSON on every collection tick.
|
|
*
|
|
* @return Microseconds to first FULL, or 0 if not yet reached.
|
|
*/
|
|
[[nodiscard]] virtual std::uint64_t
|
|
getInitialSyncDurationUs() const = 0;
|
|
[[nodiscard]] virtual std::string
|
|
strOperatingMode(OperatingMode const mode, bool const admin = false) const = 0;
|
|
[[nodiscard]] virtual std::string
|
|
strOperatingMode(bool const admin = false) const = 0;
|
|
/**
|
|
* How far this node's validated ledger trails the network's.
|
|
*
|
|
* The network target is the highest ledger sequence any connected peer
|
|
* reports holding; the result is that target minus our own validated
|
|
* sequence, floored at zero. Zero therefore means either "at the tip" or
|
|
* "no peer has told us about a newer ledger", which on a node with no
|
|
* peers is the same thing.
|
|
*
|
|
* @return Ledgers behind the network, 0 when at or ahead of the tip.
|
|
*/
|
|
[[nodiscard]] virtual std::uint32_t
|
|
getLedgersBehindNetwork() const = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Transaction processing
|
|
//
|
|
|
|
// must complete immediately
|
|
virtual void
|
|
submitTransaction(std::shared_ptr<STTx const> const&) = 0;
|
|
|
|
/**
|
|
* Process transactions as they arrive from the network or which are
|
|
* submitted by clients. Process local transactions synchronously
|
|
*
|
|
* @param transaction Transaction object
|
|
* @param bUnlimited Whether a privileged client connection submitted it.
|
|
* @param bLocal Client submission.
|
|
* @param failType fail_hard setting from transaction submission.
|
|
*/
|
|
virtual void
|
|
processTransaction(
|
|
std::shared_ptr<Transaction>& transaction,
|
|
bool bUnlimited,
|
|
bool bLocal,
|
|
FailHard failType) = 0;
|
|
|
|
/**
|
|
* Process a set of transactions synchronously, and ensuring that they are
|
|
* processed in one batch.
|
|
*
|
|
* @param set Transaction object set
|
|
*/
|
|
virtual void
|
|
processTransactionSet(CanonicalTXSet const& set) = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Owner functions
|
|
//
|
|
|
|
virtual json::Value
|
|
getOwnerInfo(std::shared_ptr<ReadView const> lpLedger, AccountID const& account) = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Book functions
|
|
//
|
|
|
|
virtual void
|
|
getBookPage(
|
|
std::shared_ptr<ReadView const>& lpLedger,
|
|
Book const& book,
|
|
AccountID const& uTakerID,
|
|
bool const bProof,
|
|
unsigned int iLimit,
|
|
json::Value const& jvMarker,
|
|
json::Value& jvResult) = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// ledger proposal/close functions
|
|
virtual bool
|
|
processTrustedProposal(RCLCxPeerPos peerPos) = 0;
|
|
|
|
virtual bool
|
|
recvValidation(std::shared_ptr<STValidation> const& val, std::string const& source) = 0;
|
|
|
|
virtual void
|
|
mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire) = 0;
|
|
|
|
// network state machine
|
|
virtual bool
|
|
beginConsensus(uint256 const& netLCL, std::unique_ptr<std::stringstream> const& clog) = 0;
|
|
virtual void
|
|
endConsensus(std::unique_ptr<std::stringstream> const& clog) = 0;
|
|
virtual void
|
|
setStandAlone() = 0;
|
|
virtual void
|
|
setStateTimer() = 0;
|
|
|
|
virtual void
|
|
setNeedNetworkLedger() = 0;
|
|
virtual void
|
|
clearNeedNetworkLedger() = 0;
|
|
virtual bool
|
|
isNeedNetworkLedger() = 0;
|
|
virtual bool
|
|
isFull() = 0;
|
|
virtual void
|
|
setMode(OperatingMode om) = 0;
|
|
virtual bool
|
|
isBlocked() = 0;
|
|
virtual bool
|
|
isAmendmentBlocked() = 0;
|
|
virtual void
|
|
setAmendmentBlocked() = 0;
|
|
virtual bool
|
|
isAmendmentWarned() = 0;
|
|
virtual void
|
|
setAmendmentWarned() = 0;
|
|
virtual void
|
|
clearAmendmentWarned() = 0;
|
|
virtual bool
|
|
isUNLBlocked() = 0;
|
|
virtual void
|
|
setUNLBlocked() = 0;
|
|
virtual void
|
|
clearUNLBlocked() = 0;
|
|
virtual void
|
|
consensusViewChange() = 0;
|
|
|
|
virtual json::Value
|
|
getConsensusInfo() = 0;
|
|
virtual json::Value
|
|
getServerInfo(bool human, bool admin, bool counters) = 0;
|
|
virtual void
|
|
clearLedgerFetch() = 0;
|
|
virtual json::Value
|
|
getLedgerFetchInfo() = 0;
|
|
|
|
/**
|
|
* Accepts the current transaction tree, return the new ledger's sequence
|
|
*
|
|
* This API is only used via RPC with the server in STANDALONE mode and
|
|
* performs a virtual consensus round, with all the transactions we are
|
|
* proposing being accepted.
|
|
*/
|
|
virtual std::uint32_t
|
|
acceptLedger(std::optional<std::chrono::milliseconds> consensusDelay = std::nullopt) = 0;
|
|
|
|
virtual void
|
|
reportFeeChange() = 0;
|
|
|
|
virtual void
|
|
updateLocalTx(ReadView const& newValidLedger) = 0;
|
|
virtual std::size_t
|
|
getLocalTxCount() = 0;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Monitoring: publisher side
|
|
//
|
|
virtual void
|
|
pubLedger(std::shared_ptr<ReadView const> const& lpAccepted) = 0;
|
|
virtual void
|
|
pubProposedTransaction(
|
|
std::shared_ptr<ReadView const> const& ledger,
|
|
std::shared_ptr<STTx const> const& transaction,
|
|
TER result) = 0;
|
|
virtual void
|
|
pubValidation(std::shared_ptr<STValidation> const& val) = 0;
|
|
|
|
virtual void
|
|
stateAccounting(json::Value& obj) = 0;
|
|
|
|
/**
|
|
* Total number of (book, subscriber) entries currently tracked.
|
|
*
|
|
* Counts every weak_ptr stored across every book in subBook_, NOT the
|
|
* number of distinct subscribers and NOT the number of distinct
|
|
* books: a single subscriber following N books contributes N entries.
|
|
*
|
|
* @note Diagnostic accessor; intended for tests and operator visibility
|
|
* into per-book subscription state. The returned value is a
|
|
* snapshot under the subscription lock.
|
|
*/
|
|
virtual std::size_t
|
|
getBookSubscribersCount() = 0;
|
|
};
|
|
|
|
} // namespace xrpl
|