diff --git a/AccountTx_8cpp_source.html b/AccountTx_8cpp_source.html index 59cf13bdc0..22d6baad18 100644 --- a/AccountTx_8cpp_source.html +++ b/AccountTx_8cpp_source.html @@ -426,7 +426,7 @@ $(function() {
348 txnMeta->getJson(JsonOptions::include_date);
349 insertDeliveredAmount(
350 jvObj[jss::meta], context, txn, *txnMeta);
-
351 insertNFTSyntheticInJson(jvObj, sttx, *txnMeta);
+
351 RPC::insertNFTSyntheticInJson(jvObj, sttx, *txnMeta);
352 RPC::insertMPTokenIssuanceID(
353 jvObj[jss::meta], sttx, *txnMeta);
354 }
@@ -584,6 +584,7 @@ $(function() {
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
Json::uintValue
@ uintValue
unsigned integer value
Definition: json_value.h:41
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:318
+
ripple::RPC::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:34
ripple::RPC::LedgerShortcut
LedgerShortcut
Definition: RPCHelpers.h:130
ripple::RPC::insertMPTokenIssuanceID
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition: MPTokenIssuanceID.cpp:64
ripple::RPC::insertDeliverMax
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition: DeliverMax.cpp:28
@@ -600,7 +601,6 @@ $(function() {
ripple::rpcLGR_IDX_MALFORMED
@ rpcLGR_IDX_MALFORMED
Definition: ErrorCodes.h:113
ripple::rpcNOT_ENABLED
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:59
ripple::rpcNOT_SYNCED
@ rpcNOT_SYNCED
Definition: ErrorCodes.h:67
-
ripple::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:33
ripple::doAccountTxJson
Json::Value doAccountTxJson(RPC::JsonContext &context)
Definition: AccountTx.cpp:404
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:125
diff --git a/Application_8cpp_source.html b/Application_8cpp_source.html index 3bb9939c4d..2de563dcff 100644 --- a/Application_8cpp_source.html +++ b/Application_8cpp_source.html @@ -2562,7 +2562,7 @@ $(function() {
ripple::make_Application
std::unique_ptr< Application > make_Application(std::unique_ptr< Config > config, std::unique_ptr< Logs > logs, std::unique_ptr< TimeKeeper > timeKeeper)
Definition: Application.cpp:2189
ripple::make_ServerHandler
std::unique_ptr< ServerHandler > make_ServerHandler(Application &app, boost::asio::io_service &io_service, JobQueue &jobQueue, NetworkOPs &networkOPs, Resource::Manager &resourceManager, CollectorManager &cm)
Definition: ServerHandler.cpp:1268
ripple::initAccountIdCache
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
Definition: AccountID.cpp:107
-
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4838
+
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4840
ripple::Endpoints
std::unordered_map< std::string, boost::asio::ip::tcp::endpoint > Endpoints
Definition: ServerImpl.h:39
ripple::hotACCOUNT_NODE
@ hotACCOUNT_NODE
Definition: NodeObject.h:35
ripple::getNodeIdentity
std::pair< PublicKey, SecretKey > getNodeIdentity(Application &app, boost::program_options::variables_map const &cmdline)
The cryptographic credentials identifying this server instance.
Definition: NodeIdentity.cpp:29
diff --git a/NFTSyntheticSerializer_8cpp_source.html b/NFTSyntheticSerializer_8cpp_source.html index af750f9e37..0621600cdb 100644 --- a/NFTSyntheticSerializer_8cpp_source.html +++ b/NFTSyntheticSerializer_8cpp_source.html @@ -106,23 +106,25 @@ $(function() {
28#include <memory>
29
30namespace ripple {
-
31
-
32void
-
33insertNFTSyntheticInJson(
-
34 Json::Value& response,
-
35 std::shared_ptr<STTx const> const& transaction,
-
36 TxMeta const& transactionMeta)
-
37{
-
38 insertNFTokenID(response[jss::meta], transaction, transactionMeta);
-
39 insertNFTokenOfferID(response[jss::meta], transaction, transactionMeta);
-
40}
-
41
-
42} // namespace ripple
+
31namespace RPC {
+
32
+
33void
+
34insertNFTSyntheticInJson(
+
35 Json::Value& response,
+
36 std::shared_ptr<STTx const> const& transaction,
+
37 TxMeta const& transactionMeta)
+
38{
+
39 insertNFTokenID(response[jss::meta], transaction, transactionMeta);
+
40 insertNFTokenOfferID(response[jss::meta], transaction, transactionMeta);
+
41}
+
42
+
43} // namespace RPC
+
44} // namespace ripple
Json::Value
Represents a JSON value.
Definition: json_value.h:150
ripple::TxMeta
Definition: TxMeta.h:35
memory
+
ripple::RPC::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:34
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:33
ripple::insertNFTokenOfferID
void insertNFTokenOfferID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition: NFTokenOfferID.cpp:72
ripple::insertNFTokenID
void insertNFTokenID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition: NFTokenID.cpp:172
std::shared_ptr
diff --git a/NFTSyntheticSerializer_8h_source.html b/NFTSyntheticSerializer_8h_source.html index 45980626d0..56f4f1809e 100644 --- a/NFTSyntheticSerializer_8h_source.html +++ b/NFTSyntheticSerializer_8h_source.html @@ -106,18 +106,21 @@ $(function() {
28
29namespace ripple {
30
-
36void
-
37insertNFTSyntheticInJson(
-
38 Json::Value&,
-
39 std::shared_ptr<STTx const> const&,
-
40 TxMeta const&);
-
43} // namespace ripple
-
44
-
45#endif
+
31namespace RPC {
+
32
+
38void
+
39insertNFTSyntheticInJson(
+
40 Json::Value&,
+
41 std::shared_ptr<STTx const> const&,
+
42 TxMeta const&);
+
45} // namespace RPC
+
46} // namespace ripple
+
47
+
48#endif
Json::Value
Represents a JSON value.
Definition: json_value.h:150
memory
+
ripple::RPC::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:34
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:33
std::shared_ptr
diff --git a/NetworkOPs_8cpp_source.html b/NetworkOPs_8cpp_source.html index 97d9ef1882..8afa6412e8 100644 --- a/NetworkOPs_8cpp_source.html +++ b/NetworkOPs_8cpp_source.html @@ -141,4742 +141,4744 @@ $(function() {
63#include <xrpl/protocol/BuildInfo.h>
64#include <xrpl/protocol/Feature.h>
65#include <xrpl/protocol/MultiApiJson.h>
-
66#include <xrpl/protocol/RPCErr.h>
-
67#include <xrpl/protocol/TxFlags.h>
-
68#include <xrpl/protocol/jss.h>
-
69#include <xrpl/resource/Fees.h>
-
70#include <xrpl/resource/ResourceManager.h>
-
71
-
72#include <boost/asio/ip/host_name.hpp>
-
73#include <boost/asio/steady_timer.hpp>
-
74
-
75#include <algorithm>
-
76#include <exception>
-
77#include <mutex>
-
78#include <optional>
-
79#include <set>
-
80#include <sstream>
-
81#include <string>
-
82#include <tuple>
-
83#include <unordered_map>
-
84
-
85namespace ripple {
-
86
-
87class NetworkOPsImp final : public NetworkOPs
-
88{
-
93 class TransactionStatus
-
94 {
-
95 public:
-
96 std::shared_ptr<Transaction> const transaction;
-
97 bool const admin;
-
98 bool const local;
-
99 FailHard const failType;
-
100 bool applied = false;
-
101 TER result;
-
102
-
103 TransactionStatus(
-
104 std::shared_ptr<Transaction> t,
-
105 bool a,
-
106 bool l,
-
107 FailHard f)
-
108 : transaction(t), admin(a), local(l), failType(f)
-
109 {
-
110 XRPL_ASSERT(
-
111 local || failType == FailHard::no,
-
112 "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : "
-
113 "valid inputs");
-
114 }
-
115 };
-
116
-
120 enum class DispatchState : unsigned char {
-
121 none,
-
122 scheduled,
-
123 running,
-
124 };
-
125
-
126 static std::array<char const*, 5> const states_;
-
127
-
142 class StateAccounting
-
143 {
-
144 struct Counters
-
145 {
-
146 explicit Counters() = default;
-
147
-
148 std::uint64_t transitions = 0;
-
149 std::chrono::microseconds dur = std::chrono::microseconds(0);
-
150 };
-
151
-
152 OperatingMode mode_ = OperatingMode::DISCONNECTED;
-
153 std::array<Counters, 5> counters_;
-
154 mutable std::mutex mutex_;
-
155 std::chrono::steady_clock::time_point start_ =
-
156 std::chrono::steady_clock::now();
-
157 std::chrono::steady_clock::time_point const processStart_ = start_;
-
158 std::uint64_t initialSyncUs_{0};
-
159 static std::array<Json::StaticString const, 5> const states_;
-
160
-
161 public:
-
162 explicit StateAccounting()
-
163 {
-
164 counters_[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
-
165 .transitions = 1;
-
166 }
-
167
-
174 void
-
175 mode(OperatingMode om);
-
176
-
182 void
-
183 json(Json::Value& obj) const;
-
184
-
185 struct CounterData
-
186 {
-
187 decltype(counters_) counters;
-
188 decltype(mode_) mode;
-
189 decltype(start_) start;
-
190 decltype(initialSyncUs_) initialSyncUs;
-
191 };
-
192
-
193 CounterData
-
194 getCounterData() const
-
195 {
-
196 std::lock_guard lock(mutex_);
-
197 return {counters_, mode_, start_, initialSyncUs_};
-
198 }
-
199 };
-
200
-
202 struct ServerFeeSummary
-
203 {
-
204 ServerFeeSummary() = default;
-
205
-
206 ServerFeeSummary(
-
207 XRPAmount fee,
-
208 TxQ::Metrics&& escalationMetrics,
-
209 LoadFeeTrack const& loadFeeTrack);
-
210 bool
-
211 operator!=(ServerFeeSummary const& b) const;
-
212
-
213 bool
-
214 operator==(ServerFeeSummary const& b) const
-
215 {
-
216 return !(*this != b);
-
217 }
-
218
-
219 std::uint32_t loadFactorServer = 256;
-
220 std::uint32_t loadBaseServer = 256;
-
221 XRPAmount baseFee{10};
-
222 std::optional<TxQ::Metrics> em = std::nullopt;
-
223 };
-
224
-
225public:
-
226 NetworkOPsImp(
-
227 Application& app,
-
228 NetworkOPs::clock_type& clock,
-
229 bool standalone,
-
230 std::size_t minPeerCount,
-
231 bool start_valid,
-
232 JobQueue& job_queue,
-
233 LedgerMaster& ledgerMaster,
-
234 ValidatorKeys const& validatorKeys,
-
235 boost::asio::io_service& io_svc,
-
236 beast::Journal journal,
-
237 beast::insight::Collector::ptr const& collector)
-
238 : app_(app)
-
239 , m_journal(journal)
-
240 , m_localTX(make_LocalTxs())
-
241 , mMode(start_valid ? OperatingMode::FULL : OperatingMode::DISCONNECTED)
-
242 , heartbeatTimer_(io_svc)
-
243 , clusterTimer_(io_svc)
-
244 , accountHistoryTxTimer_(io_svc)
-
245 , mConsensus(
-
246 app,
-
247 make_FeeVote(
-
248 setup_FeeVote(app_.config().section("voting")),
-
249 app_.logs().journal("FeeVote")),
-
250 ledgerMaster,
-
251 *m_localTX,
-
252 app.getInboundTransactions(),
-
253 beast::get_abstract_clock<std::chrono::steady_clock>(),
-
254 validatorKeys,
-
255 app_.logs().journal("LedgerConsensus"))
-
256 , validatorPK_(
-
257 validatorKeys.keys ? validatorKeys.keys->publicKey
-
258 : decltype(validatorPK_){})
-
259 , validatorMasterPK_(
-
260 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
-
261 : decltype(validatorMasterPK_){})
-
262 , m_ledgerMaster(ledgerMaster)
-
263 , m_job_queue(job_queue)
-
264 , m_standalone(standalone)
-
265 , minPeerCount_(start_valid ? 0 : minPeerCount)
-
266 , m_stats(std::bind(&NetworkOPsImp::collect_metrics, this), collector)
-
267 {
-
268 }
-
269
-
270 ~NetworkOPsImp() override
-
271 {
-
272 // This clear() is necessary to ensure the shared_ptrs in this map get
-
273 // destroyed NOW because the objects in this map invoke methods on this
-
274 // class when they are destroyed
-
275 mRpcSubMap.clear();
-
276 }
-
277
-
278public:
-
279 OperatingMode
-
280 getOperatingMode() const override;
-
281
-
282 std::string
-
283 strOperatingMode(OperatingMode const mode, bool const admin) const override;
-
284
-
285 std::string
-
286 strOperatingMode(bool const admin = false) const override;
-
287
-
288 //
-
289 // Transaction operations.
-
290 //
-
291
-
292 // Must complete immediately.
-
293 void
-
294 submitTransaction(std::shared_ptr<STTx const> const&) override;
-
295
-
296 void
-
297 processTransaction(
-
298 std::shared_ptr<Transaction>& transaction,
-
299 bool bUnlimited,
-
300 bool bLocal,
-
301 FailHard failType) override;
-
302
-
303 void
-
304 processTransactionSet(CanonicalTXSet const& set) override;
-
305
-
314 void
-
315 doTransactionSync(
-
316 std::shared_ptr<Transaction> transaction,
-
317 bool bUnlimited,
-
318 FailHard failType);
-
319
-
329 void
-
330 doTransactionAsync(
-
331 std::shared_ptr<Transaction> transaction,
-
332 bool bUnlimited,
-
333 FailHard failtype);
-
334
-
335private:
-
336 bool
-
337 preProcessTransaction(std::shared_ptr<Transaction>& transaction);
-
338
-
339 void
-
340 doTransactionSyncBatch(
-
341 std::unique_lock<std::mutex>& lock,
-
342 std::function<bool(std::unique_lock<std::mutex> const&)> retryCallback);
-
343
-
344public:
-
348 void
-
349 transactionBatch();
-
350
-
356 void
-
357 apply(std::unique_lock<std::mutex>& batchLock);
-
358
-
359 //
-
360 // Owner functions.
-
361 //
-
362
-
363 Json::Value
-
364 getOwnerInfo(
-
365 std::shared_ptr<ReadView const> lpLedger,
-
366 AccountID const& account) override;
-
367
-
368 //
-
369 // Book functions.
-
370 //
-
371
-
372 void
-
373 getBookPage(
-
374 std::shared_ptr<ReadView const>& lpLedger,
-
375 Book const&,
-
376 AccountID const& uTakerID,
-
377 bool const bProof,
-
378 unsigned int iLimit,
-
379 Json::Value const& jvMarker,
-
380 Json::Value& jvResult) override;
-
381
-
382 // Ledger proposal/close functions.
-
383 bool
-
384 processTrustedProposal(RCLCxPeerPos proposal) override;
-
385
-
386 bool
-
387 recvValidation(
-
388 std::shared_ptr<STValidation> const& val,
-
389 std::string const& source) override;
-
390
-
391 void
-
392 mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire) override;
-
393
-
394 // Network state machine.
-
395
-
396 // Used for the "jump" case.
-
397private:
-
398 void
-
399 switchLastClosedLedger(std::shared_ptr<Ledger const> const& newLCL);
-
400 bool
-
401 checkLastClosedLedger(Overlay::PeerSequence const&, uint256& networkClosed);
-
402
-
403public:
-
404 bool
-
405 beginConsensus(
-
406 uint256 const& networkClosed,
-
407 std::unique_ptr<std::stringstream> const& clog) override;
-
408 void
-
409 endConsensus(std::unique_ptr<std::stringstream> const& clog) override;
-
410 void
-
411 setStandAlone() override;
-
412
-
416 void
-
417 setStateTimer() override;
-
418
-
419 void
-
420 setNeedNetworkLedger() override;
-
421 void
-
422 clearNeedNetworkLedger() override;
-
423 bool
-
424 isNeedNetworkLedger() override;
-
425 bool
-
426 isFull() override;
-
427
-
428 void
-
429 setMode(OperatingMode om) override;
-
430
-
431 bool
-
432 isBlocked() override;
-
433 bool
-
434 isAmendmentBlocked() override;
-
435 void
-
436 setAmendmentBlocked() override;
-
437 bool
-
438 isAmendmentWarned() override;
-
439 void
-
440 setAmendmentWarned() override;
-
441 void
-
442 clearAmendmentWarned() override;
-
443 bool
-
444 isUNLBlocked() override;
-
445 void
-
446 setUNLBlocked() override;
-
447 void
-
448 clearUNLBlocked() override;
-
449 void
-
450 consensusViewChange() override;
-
451
-
452 Json::Value
-
453 getConsensusInfo() override;
-
454 Json::Value
-
455 getServerInfo(bool human, bool admin, bool counters) override;
-
456 void
-
457 clearLedgerFetch() override;
-
458 Json::Value
-
459 getLedgerFetchInfo() override;
-
460 std::uint32_t
-
461 acceptLedger(
-
462 std::optional<std::chrono::milliseconds> consensusDelay) override;
-
463 void
-
464 reportFeeChange() override;
-
465 void
-
466 reportConsensusStateChange(ConsensusPhase phase);
-
467
-
468 void
-
469 updateLocalTx(ReadView const& view) override;
-
470 std::size_t
-
471 getLocalTxCount() override;
-
472
-
473 //
-
474 // Monitoring: publisher side.
-
475 //
-
476 void
-
477 pubLedger(std::shared_ptr<ReadView const> const& lpAccepted) override;
-
478 void
-
479 pubProposedTransaction(
-
480 std::shared_ptr<ReadView const> const& ledger,
-
481 std::shared_ptr<STTx const> const& transaction,
-
482 TER result) override;
-
483 void
-
484 pubValidation(std::shared_ptr<STValidation> const& val) override;
-
485
-
486 //--------------------------------------------------------------------------
-
487 //
-
488 // InfoSub::Source.
-
489 //
-
490 void
-
491 subAccount(
-
492 InfoSub::ref ispListener,
-
493 hash_set<AccountID> const& vnaAccountIDs,
-
494 bool rt) override;
-
495 void
-
496 unsubAccount(
-
497 InfoSub::ref ispListener,
-
498 hash_set<AccountID> const& vnaAccountIDs,
-
499 bool rt) override;
-
500
-
501 // Just remove the subscription from the tracking
-
502 // not from the InfoSub. Needed for InfoSub destruction
-
503 void
-
504 unsubAccountInternal(
-
505 std::uint64_t seq,
-
506 hash_set<AccountID> const& vnaAccountIDs,
-
507 bool rt) override;
-
508
-
509 error_code_i
-
510 subAccountHistory(InfoSub::ref ispListener, AccountID const& account)
-
511 override;
-
512 void
-
513 unsubAccountHistory(
-
514 InfoSub::ref ispListener,
-
515 AccountID const& account,
-
516 bool historyOnly) override;
-
517
-
518 void
-
519 unsubAccountHistoryInternal(
-
520 std::uint64_t seq,
-
521 AccountID const& account,
-
522 bool historyOnly) override;
-
523
-
524 bool
-
525 subLedger(InfoSub::ref ispListener, Json::Value& jvResult) override;
-
526 bool
-
527 unsubLedger(std::uint64_t uListener) override;
-
528
-
529 bool
-
530 subBookChanges(InfoSub::ref ispListener) override;
-
531 bool
-
532 unsubBookChanges(std::uint64_t uListener) override;
-
533
-
534 bool
-
535 subServer(InfoSub::ref ispListener, Json::Value& jvResult, bool admin)
-
536 override;
-
537 bool
-
538 unsubServer(std::uint64_t uListener) override;
-
539
-
540 bool
-
541 subBook(InfoSub::ref ispListener, Book const&) override;
-
542 bool
-
543 unsubBook(std::uint64_t uListener, Book const&) override;
-
544
-
545 bool
-
546 subManifests(InfoSub::ref ispListener) override;
-
547 bool
-
548 unsubManifests(std::uint64_t uListener) override;
-
549 void
-
550 pubManifest(Manifest const&) override;
-
551
-
552 bool
-
553 subTransactions(InfoSub::ref ispListener) override;
-
554 bool
-
555 unsubTransactions(std::uint64_t uListener) override;
-
556
-
557 bool
-
558 subRTTransactions(InfoSub::ref ispListener) override;
-
559 bool
-
560 unsubRTTransactions(std::uint64_t uListener) override;
-
561
-
562 bool
-
563 subValidations(InfoSub::ref ispListener) override;
-
564 bool
-
565 unsubValidations(std::uint64_t uListener) override;
-
566
-
567 bool
-
568 subPeerStatus(InfoSub::ref ispListener) override;
-
569 bool
-
570 unsubPeerStatus(std::uint64_t uListener) override;
-
571 void
-
572 pubPeerStatus(std::function<Json::Value(void)> const&) override;
-
573
-
574 bool
-
575 subConsensus(InfoSub::ref ispListener) override;
-
576 bool
-
577 unsubConsensus(std::uint64_t uListener) override;
-
578
-
579 InfoSub::pointer
-
580 findRpcSub(std::string const& strUrl) override;
-
581 InfoSub::pointer
-
582 addRpcSub(std::string const& strUrl, InfoSub::ref) override;
-
583 bool
-
584 tryRemoveRpcSub(std::string const& strUrl) override;
-
585
-
586 void
-
587 stop() override
-
588 {
-
589 {
-
590 boost::system::error_code ec;
-
591 heartbeatTimer_.cancel(ec);
-
592 if (ec)
-
593 {
-
594 JLOG(m_journal.error())
-
595 << "NetworkOPs: heartbeatTimer cancel error: "
-
596 << ec.message();
-
597 }
-
598
-
599 ec.clear();
-
600 clusterTimer_.cancel(ec);
-
601 if (ec)
-
602 {
-
603 JLOG(m_journal.error())
-
604 << "NetworkOPs: clusterTimer cancel error: "
-
605 << ec.message();
-
606 }
-
607
-
608 ec.clear();
-
609 accountHistoryTxTimer_.cancel(ec);
-
610 if (ec)
-
611 {
-
612 JLOG(m_journal.error())
-
613 << "NetworkOPs: accountHistoryTxTimer cancel error: "
-
614 << ec.message();
-
615 }
-
616 }
-
617 // Make sure that any waitHandlers pending in our timers are done.
-
618 using namespace std::chrono_literals;
-
619 waitHandlerCounter_.join("NetworkOPs", 1s, m_journal);
-
620 }
-
621
-
622 void
-
623 stateAccounting(Json::Value& obj) override;
-
624
-
625private:
-
626 void
-
627 setTimer(
-
628 boost::asio::steady_timer& timer,
-
629 std::chrono::milliseconds const& expiry_time,
-
630 std::function<void()> onExpire,
-
631 std::function<void()> onError);
-
632 void
-
633 setHeartbeatTimer();
-
634 void
-
635 setClusterTimer();
-
636 void
-
637 processHeartbeatTimer();
-
638 void
-
639 processClusterTimer();
-
640
-
641 MultiApiJson
-
642 transJson(
-
643 std::shared_ptr<STTx const> const& transaction,
-
644 TER result,
-
645 bool validated,
-
646 std::shared_ptr<ReadView const> const& ledger,
-
647 std::optional<std::reference_wrapper<TxMeta const>> meta);
-
648
-
649 void
-
650 pubValidatedTransaction(
-
651 std::shared_ptr<ReadView const> const& ledger,
-
652 AcceptedLedgerTx const& transaction,
-
653 bool last);
-
654
-
655 void
-
656 pubAccountTransaction(
-
657 std::shared_ptr<ReadView const> const& ledger,
-
658 AcceptedLedgerTx const& transaction,
-
659 bool last);
-
660
-
661 void
-
662 pubProposedAccountTransaction(
-
663 std::shared_ptr<ReadView const> const& ledger,
-
664 std::shared_ptr<STTx const> const& transaction,
-
665 TER result);
-
666
-
667 void
-
668 pubServer();
-
669 void
-
670 pubConsensus(ConsensusPhase phase);
-
671
-
672 std::string
-
673 getHostId(bool forAdmin);
-
674
-
675private:
-
676 using SubMapType = hash_map<std::uint64_t, InfoSub::wptr>;
-
677 using SubInfoMapType = hash_map<AccountID, SubMapType>;
-
678 using subRpcMapType = hash_map<std::string, InfoSub::pointer>;
-
679
-
680 /*
-
681 * With a validated ledger to separate history and future, the node
-
682 * streams historical txns with negative indexes starting from -1,
-
683 * and streams future txns starting from index 0.
-
684 * The SubAccountHistoryIndex struct maintains these indexes.
-
685 * It also has a flag stopHistorical_ for stopping streaming
-
686 * the historical txns.
-
687 */
-
688 struct SubAccountHistoryIndex
-
689 {
-
690 AccountID const accountId_;
-
691 // forward
-
692 std::uint32_t forwardTxIndex_;
-
693 // separate backward and forward
-
694 std::uint32_t separationLedgerSeq_;
-
695 // history, backward
-
696 std::uint32_t historyLastLedgerSeq_;
-
697 std::int32_t historyTxIndex_;
-
698 bool haveHistorical_;
-
699 std::atomic<bool> stopHistorical_;
-
700
-
701 SubAccountHistoryIndex(AccountID const& accountId)
-
702 : accountId_(accountId)
-
703 , forwardTxIndex_(0)
-
704 , separationLedgerSeq_(0)
-
705 , historyLastLedgerSeq_(0)
-
706 , historyTxIndex_(-1)
-
707 , haveHistorical_(false)
-
708 , stopHistorical_(false)
-
709 {
-
710 }
-
711 };
-
712 struct SubAccountHistoryInfo
-
713 {
-
714 InfoSub::pointer sink_;
-
715 std::shared_ptr<SubAccountHistoryIndex> index_;
-
716 };
-
717 struct SubAccountHistoryInfoWeak
-
718 {
-
719 InfoSub::wptr sinkWptr_;
-
720 std::shared_ptr<SubAccountHistoryIndex> index_;
-
721 };
-
722 using SubAccountHistoryMapType =
-
723 hash_map<AccountID, hash_map<std::uint64_t, SubAccountHistoryInfoWeak>>;
-
724
-
728 void
-
729 subAccountHistoryStart(
-
730 std::shared_ptr<ReadView const> const& ledger,
-
731 SubAccountHistoryInfoWeak& subInfo);
-
732 void
-
733 addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo);
-
734 void
-
735 setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo);
-
736
-
737 Application& app_;
-
738 beast::Journal m_journal;
-
739
-
740 std::unique_ptr<LocalTxs> m_localTX;
-
741
-
742 std::recursive_mutex mSubLock;
-
743
-
744 std::atomic<OperatingMode> mMode;
-
745
-
746 std::atomic<bool> needNetworkLedger_{false};
-
747 std::atomic<bool> amendmentBlocked_{false};
-
748 std::atomic<bool> amendmentWarned_{false};
-
749 std::atomic<bool> unlBlocked_{false};
-
750
-
751 ClosureCounter<void, boost::system::error_code const&> waitHandlerCounter_;
-
752 boost::asio::steady_timer heartbeatTimer_;
-
753 boost::asio::steady_timer clusterTimer_;
-
754 boost::asio::steady_timer accountHistoryTxTimer_;
-
755
-
756 RCLConsensus mConsensus;
-
757
-
758 std::optional<PublicKey> const validatorPK_;
-
759 std::optional<PublicKey> const validatorMasterPK_;
-
760
-
761 ConsensusPhase mLastConsensusPhase;
-
762
-
763 LedgerMaster& m_ledgerMaster;
-
764
-
765 SubInfoMapType mSubAccount;
-
766 SubInfoMapType mSubRTAccount;
-
767
-
768 subRpcMapType mRpcSubMap;
-
769
-
770 SubAccountHistoryMapType mSubAccountHistory;
-
771
-
772 enum SubTypes {
-
773 sLedger, // Accepted ledgers.
-
774 sManifests, // Received validator manifests.
-
775 sServer, // When server changes connectivity state.
-
776 sTransactions, // All accepted transactions.
-
777 sRTTransactions, // All proposed and accepted transactions.
-
778 sValidations, // Received validations.
-
779 sPeerStatus, // Peer status changes.
-
780 sConsensusPhase, // Consensus phase
-
781 sBookChanges, // Per-ledger order book changes
-
782 sLastEntry // Any new entry must be ADDED ABOVE this one
-
783 };
-
784
-
785 std::array<SubMapType, SubTypes::sLastEntry> mStreamMaps;
-
786
-
787 ServerFeeSummary mLastFeeSummary;
-
788
-
789 JobQueue& m_job_queue;
-
790
-
791 // Whether we are in standalone mode.
-
792 bool const m_standalone;
-
793
-
794 // The number of nodes that we need to consider ourselves connected.
-
795 std::size_t const minPeerCount_;
-
796
-
797 // Transaction batching.
-
798 std::condition_variable mCond;
-
799 std::mutex mMutex;
-
800 DispatchState mDispatchState = DispatchState::none;
-
801 std::vector<TransactionStatus> mTransactions;
-
802
-
803 StateAccounting accounting_{};
-
804
-
805 std::set<uint256> pendingValidations_;
-
806 std::mutex validationsMutex_;
-
807
-
808private:
-
809 struct Stats
-
810 {
-
811 template <class Handler>
-
812 Stats(
-
813 Handler const& handler,
-
814 beast::insight::Collector::ptr const& collector)
-
815 : hook(collector->make_hook(handler))
-
816 , disconnected_duration(collector->make_gauge(
-
817 "State_Accounting",
-
818 "Disconnected_duration"))
-
819 , connected_duration(collector->make_gauge(
-
820 "State_Accounting",
-
821 "Connected_duration"))
-
822 , syncing_duration(
-
823 collector->make_gauge("State_Accounting", "Syncing_duration"))
-
824 , tracking_duration(collector->make_gauge(
-
825 "State_Accounting",
-
826 "Tracking_duration"))
-
827 , full_duration(
-
828 collector->make_gauge("State_Accounting", "Full_duration"))
-
829 , disconnected_transitions(collector->make_gauge(
-
830 "State_Accounting",
-
831 "Disconnected_transitions"))
-
832 , connected_transitions(collector->make_gauge(
-
833 "State_Accounting",
-
834 "Connected_transitions"))
-
835 , syncing_transitions(collector->make_gauge(
-
836 "State_Accounting",
-
837 "Syncing_transitions"))
-
838 , tracking_transitions(collector->make_gauge(
-
839 "State_Accounting",
-
840 "Tracking_transitions"))
-
841 , full_transitions(
-
842 collector->make_gauge("State_Accounting", "Full_transitions"))
-
843 {
-
844 }
-
845
-
846 beast::insight::Hook hook;
-
847 beast::insight::Gauge disconnected_duration;
-
848 beast::insight::Gauge connected_duration;
-
849 beast::insight::Gauge syncing_duration;
-
850 beast::insight::Gauge tracking_duration;
-
851 beast::insight::Gauge full_duration;
-
852
-
853 beast::insight::Gauge disconnected_transitions;
-
854 beast::insight::Gauge connected_transitions;
-
855 beast::insight::Gauge syncing_transitions;
-
856 beast::insight::Gauge tracking_transitions;
-
857 beast::insight::Gauge full_transitions;
-
858 };
-
859
-
860 std::mutex m_statsMutex; // Mutex to lock m_stats
-
861 Stats m_stats;
-
862
-
863private:
-
864 void
-
865 collect_metrics();
-
866};
-
867
-
868//------------------------------------------------------------------------------
-
869
-
870static std::array<char const*, 5> const stateNames{
-
871 {"disconnected", "connected", "syncing", "tracking", "full"}};
-
872
-
873std::array<char const*, 5> const NetworkOPsImp::states_ = stateNames;
-
874
-
875std::array<Json::StaticString const, 5> const
-
876 NetworkOPsImp::StateAccounting::states_ = {
-
877 {Json::StaticString(stateNames[0]),
-
878 Json::StaticString(stateNames[1]),
-
879 Json::StaticString(stateNames[2]),
-
880 Json::StaticString(stateNames[3]),
-
881 Json::StaticString(stateNames[4])}};
-
882
-
883static auto const genesisAccountId = calcAccountID(
-
884 generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase"))
-
885 .first);
-
886
-
887//------------------------------------------------------------------------------
-
888inline OperatingMode
-
889NetworkOPsImp::getOperatingMode() const
-
890{
-
891 return mMode;
-
892}
-
893
-
894inline std::string
-
895NetworkOPsImp::strOperatingMode(bool const admin /* = false */) const
-
896{
-
897 return strOperatingMode(mMode, admin);
-
898}
-
899
-
900inline void
-
901NetworkOPsImp::setStandAlone()
-
902{
-
903 setMode(OperatingMode::FULL);
-
904}
-
905
-
906inline void
-
907NetworkOPsImp::setNeedNetworkLedger()
-
908{
-
909 needNetworkLedger_ = true;
-
910}
-
911
-
912inline void
-
913NetworkOPsImp::clearNeedNetworkLedger()
-
914{
-
915 needNetworkLedger_ = false;
-
916}
-
917
-
918inline bool
-
919NetworkOPsImp::isNeedNetworkLedger()
-
920{
-
921 return needNetworkLedger_;
-
922}
-
923
-
924inline bool
-
925NetworkOPsImp::isFull()
-
926{
-
927 return !needNetworkLedger_ && (mMode == OperatingMode::FULL);
-
928}
-
929
-
930std::string
-
931NetworkOPsImp::getHostId(bool forAdmin)
-
932{
-
933 static std::string const hostname = boost::asio::ip::host_name();
-
934
-
935 if (forAdmin)
-
936 return hostname;
-
937
-
938 // For non-admin uses hash the node public key into a
-
939 // single RFC1751 word:
-
940 static std::string const shroudedHostId = [this]() {
-
941 auto const& id = app_.nodeIdentity();
-
942
-
943 return RFC1751::getWordFromBlob(id.first.data(), id.first.size());
-
944 }();
-
945
-
946 return shroudedHostId;
-
947}
-
948
-
949void
-
950NetworkOPsImp::setStateTimer()
-
951{
-
952 setHeartbeatTimer();
-
953
-
954 // Only do this work if a cluster is configured
-
955 if (app_.cluster().size() != 0)
-
956 setClusterTimer();
-
957}
-
958
-
959void
-
960NetworkOPsImp::setTimer(
-
961 boost::asio::steady_timer& timer,
-
962 std::chrono::milliseconds const& expiry_time,
-
963 std::function<void()> onExpire,
-
964 std::function<void()> onError)
-
965{
-
966 // Only start the timer if waitHandlerCounter_ is not yet joined.
-
967 if (auto optionalCountedHandler = waitHandlerCounter_.wrap(
-
968 [this, onExpire, onError](boost::system::error_code const& e) {
-
969 if ((e.value() == boost::system::errc::success) &&
-
970 (!m_job_queue.isStopped()))
-
971 {
-
972 onExpire();
-
973 }
-
974 // Recover as best we can if an unexpected error occurs.
-
975 if (e.value() != boost::system::errc::success &&
-
976 e.value() != boost::asio::error::operation_aborted)
-
977 {
-
978 // Try again later and hope for the best.
-
979 JLOG(m_journal.error())
-
980 << "Timer got error '" << e.message()
-
981 << "'. Restarting timer.";
-
982 onError();
-
983 }
-
984 }))
-
985 {
-
986 timer.expires_from_now(expiry_time);
-
987 timer.async_wait(std::move(*optionalCountedHandler));
-
988 }
-
989}
-
990
-
991void
-
992NetworkOPsImp::setHeartbeatTimer()
-
993{
-
994 setTimer(
-
995 heartbeatTimer_,
-
996 mConsensus.parms().ledgerGRANULARITY,
-
997 [this]() {
-
998 m_job_queue.addJob(jtNETOP_TIMER, "NetOPs.heartbeat", [this]() {
-
999 processHeartbeatTimer();
-
1000 });
-
1001 },
-
1002 [this]() { setHeartbeatTimer(); });
-
1003}
-
1004
-
1005void
-
1006NetworkOPsImp::setClusterTimer()
-
1007{
-
1008 using namespace std::chrono_literals;
-
1009
-
1010 setTimer(
-
1011 clusterTimer_,
-
1012 10s,
-
1013 [this]() {
-
1014 m_job_queue.addJob(jtNETOP_CLUSTER, "NetOPs.cluster", [this]() {
-
1015 processClusterTimer();
-
1016 });
-
1017 },
-
1018 [this]() { setClusterTimer(); });
-
1019}
-
1020
-
1021void
-
1022NetworkOPsImp::setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
-
1023{
-
1024 JLOG(m_journal.debug()) << "Scheduling AccountHistory job for account "
-
1025 << toBase58(subInfo.index_->accountId_);
-
1026 using namespace std::chrono_literals;
-
1027 setTimer(
-
1028 accountHistoryTxTimer_,
-
1029 4s,
-
1030 [this, subInfo]() { addAccountHistoryJob(subInfo); },
-
1031 [this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
-
1032}
-
1033
-
1034void
-
1035NetworkOPsImp::processHeartbeatTimer()
-
1036{
-
1037 RclConsensusLogger clog(
-
1038 "Heartbeat Timer", mConsensus.validating(), m_journal);
-
1039 {
-
1040 std::unique_lock lock{app_.getMasterMutex()};
-
1041
-
1042 // VFALCO NOTE This is for diagnosing a crash on exit
-
1043 LoadManager& mgr(app_.getLoadManager());
-
1044 mgr.heartbeat();
-
1045
-
1046 std::size_t const numPeers = app_.overlay().size();
-
1047
-
1048 // do we have sufficient peers? If not, we are disconnected.
-
1049 if (numPeers < minPeerCount_)
-
1050 {
-
1051 if (mMode != OperatingMode::DISCONNECTED)
-
1052 {
-
1053 setMode(OperatingMode::DISCONNECTED);
-
1054 std::stringstream ss;
-
1055 ss << "Node count (" << numPeers << ") has fallen "
-
1056 << "below required minimum (" << minPeerCount_ << ").";
-
1057 JLOG(m_journal.warn()) << ss.str();
-
1058 CLOG(clog.ss()) << "set mode to DISCONNECTED: " << ss.str();
-
1059 }
-
1060 else
-
1061 {
-
1062 CLOG(clog.ss())
-
1063 << "already DISCONNECTED. too few peers (" << numPeers
-
1064 << "), need at least " << minPeerCount_;
-
1065 }
-
1066
-
1067 // MasterMutex lock need not be held to call setHeartbeatTimer()
-
1068 lock.unlock();
-
1069 // We do not call mConsensus.timerEntry until there are enough
-
1070 // peers providing meaningful inputs to consensus
-
1071 setHeartbeatTimer();
-
1072
-
1073 return;
-
1074 }
-
1075
-
1076 if (mMode == OperatingMode::DISCONNECTED)
-
1077 {
-
1078 setMode(OperatingMode::CONNECTED);
-
1079 JLOG(m_journal.info())
-
1080 << "Node count (" << numPeers << ") is sufficient.";
-
1081 CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers
-
1082 << " peers. ";
-
1083 }
-
1084
-
1085 // Check if the last validated ledger forces a change between these
-
1086 // states.
-
1087 auto origMode = mMode.load();
-
1088 CLOG(clog.ss()) << "mode: " << strOperatingMode(origMode, true);
-
1089 if (mMode == OperatingMode::SYNCING)
-
1090 setMode(OperatingMode::SYNCING);
-
1091 else if (mMode == OperatingMode::CONNECTED)
-
1092 setMode(OperatingMode::CONNECTED);
-
1093 auto newMode = mMode.load();
-
1094 if (origMode != newMode)
-
1095 {
-
1096 CLOG(clog.ss())
-
1097 << ", changing to " << strOperatingMode(newMode, true);
-
1098 }
-
1099 CLOG(clog.ss()) << ". ";
-
1100 }
-
1101
-
1102 mConsensus.timerEntry(app_.timeKeeper().closeTime(), clog.ss());
-
1103
-
1104 CLOG(clog.ss()) << "consensus phase " << to_string(mLastConsensusPhase);
-
1105 ConsensusPhase const currPhase = mConsensus.phase();
-
1106 if (mLastConsensusPhase != currPhase)
-
1107 {
-
1108 reportConsensusStateChange(currPhase);
-
1109 mLastConsensusPhase = currPhase;
-
1110 CLOG(clog.ss()) << " changed to " << to_string(mLastConsensusPhase);
-
1111 }
-
1112 CLOG(clog.ss()) << ". ";
-
1113
-
1114 setHeartbeatTimer();
-
1115}
-
1116
-
1117void
-
1118NetworkOPsImp::processClusterTimer()
-
1119{
-
1120 if (app_.cluster().size() == 0)
-
1121 return;
-
1122
-
1123 using namespace std::chrono_literals;
-
1124
-
1125 bool const update = app_.cluster().update(
-
1126 app_.nodeIdentity().first,
-
1127 "",
-
1128 (m_ledgerMaster.getValidatedLedgerAge() <= 4min)
-
1129 ? app_.getFeeTrack().getLocalFee()
-
1130 : 0,
-
1131 app_.timeKeeper().now());
-
1132
-
1133 if (!update)
-
1134 {
-
1135 JLOG(m_journal.debug()) << "Too soon to send cluster update";
-
1136 setClusterTimer();
-
1137 return;
-
1138 }
-
1139
-
1140 protocol::TMCluster cluster;
-
1141 app_.cluster().for_each([&cluster](ClusterNode const& node) {
-
1142 protocol::TMClusterNode& n = *cluster.add_clusternodes();
-
1143 n.set_publickey(toBase58(TokenType::NodePublic, node.identity()));
-
1144 n.set_reporttime(node.getReportTime().time_since_epoch().count());
-
1145 n.set_nodeload(node.getLoadFee());
-
1146 if (!node.name().empty())
-
1147 n.set_nodename(node.name());
-
1148 });
-
1149
-
1150 Resource::Gossip gossip = app_.getResourceManager().exportConsumers();
-
1151 for (auto& item : gossip.items)
-
1152 {
-
1153 protocol::TMLoadSource& node = *cluster.add_loadsources();
-
1154 node.set_name(to_string(item.address));
-
1155 node.set_cost(item.balance);
-
1156 }
-
1157 app_.overlay().foreach(send_if(
-
1158 std::make_shared<Message>(cluster, protocol::mtCLUSTER),
-
1159 peer_in_cluster()));
-
1160 setClusterTimer();
-
1161}
-
1162
-
1163//------------------------------------------------------------------------------
-
1164
-
1165std::string
-
1166NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin)
-
1167 const
-
1168{
-
1169 if (mode == OperatingMode::FULL && admin)
-
1170 {
-
1171 auto const consensusMode = mConsensus.mode();
-
1172 if (consensusMode != ConsensusMode::wrongLedger)
-
1173 {
-
1174 if (consensusMode == ConsensusMode::proposing)
-
1175 return "proposing";
-
1176
-
1177 if (mConsensus.validating())
-
1178 return "validating";
-
1179 }
-
1180 }
-
1181
-
1182 return states_[static_cast<std::size_t>(mode)];
-
1183}
-
1184
-
1185void
-
1186NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
-
1187{
-
1188 if (isNeedNetworkLedger())
-
1189 {
-
1190 // Nothing we can do if we've never been in sync
-
1191 return;
-
1192 }
-
1193
-
1194 // Enforce Network bar for batch txn
-
1195 if (iTrans->isFlag(tfInnerBatchTxn) &&
-
1196 m_ledgerMaster.getValidatedRules().enabled(featureBatch))
-
1197 {
-
1198 JLOG(m_journal.error())
-
1199 << "Submitted transaction invalid: tfInnerBatchTxn flag present.";
-
1200 return;
-
1201 }
-
1202
-
1203 // this is an asynchronous interface
-
1204 auto const trans = sterilize(*iTrans);
-
1205
-
1206 auto const txid = trans->getTransactionID();
-
1207 auto const flags = app_.getHashRouter().getFlags(txid);
-
1208
-
1209 if ((flags & SF_BAD) != 0)
-
1210 {
-
1211 JLOG(m_journal.warn()) << "Submitted transaction cached bad";
-
1212 return;
-
1213 }
-
1214
-
1215 try
-
1216 {
-
1217 auto const [validity, reason] = checkValidity(
-
1218 app_.getHashRouter(),
-
1219 *trans,
-
1220 m_ledgerMaster.getValidatedRules(),
-
1221 app_.config());
-
1222
-
1223 if (validity != Validity::Valid)
-
1224 {
-
1225 JLOG(m_journal.warn())
-
1226 << "Submitted transaction invalid: " << reason;
-
1227 return;
-
1228 }
-
1229 }
-
1230 catch (std::exception const& ex)
-
1231 {
-
1232 JLOG(m_journal.warn())
-
1233 << "Exception checking transaction " << txid << ": " << ex.what();
-
1234
-
1235 return;
-
1236 }
-
1237
-
1238 std::string reason;
-
1239
-
1240 auto tx = std::make_shared<Transaction>(trans, reason, app_);
-
1241
-
1242 m_job_queue.addJob(jtTRANSACTION, "submitTxn", [this, tx]() {
-
1243 auto t = tx;
-
1244 processTransaction(t, false, false, FailHard::no);
-
1245 });
-
1246}
-
1247
-
1248bool
-
1249NetworkOPsImp::preProcessTransaction(std::shared_ptr<Transaction>& transaction)
-
1250{
-
1251 auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
-
1252
-
1253 if ((newFlags & SF_BAD) != 0)
-
1254 {
-
1255 // cached bad
-
1256 JLOG(m_journal.warn()) << transaction->getID() << ": cached bad!\n";
-
1257 transaction->setStatus(INVALID);
-
1258 transaction->setResult(temBAD_SIGNATURE);
-
1259 return false;
-
1260 }
-
1261
-
1262 auto const view = m_ledgerMaster.getCurrentLedger();
-
1263
-
1264 // This function is called by several different parts of the codebase
-
1265 // under no circumstances will we ever accept an inner txn within a batch
-
1266 // txn from the network.
-
1267 auto const sttx = *transaction->getSTransaction();
-
1268 if (sttx.isFlag(tfInnerBatchTxn) && view->rules().enabled(featureBatch))
-
1269 {
-
1270 transaction->setStatus(INVALID);
-
1271 transaction->setResult(temINVALID_FLAG);
-
1272 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
-
1273 return false;
-
1274 }
-
1275
-
1276 // NOTE eahennis - I think this check is redundant,
-
1277 // but I'm not 100% sure yet.
-
1278 // If so, only cost is looking up HashRouter flags.
-
1279 auto const [validity, reason] =
-
1280 checkValidity(app_.getHashRouter(), sttx, view->rules(), app_.config());
-
1281 XRPL_ASSERT(
-
1282 validity == Validity::Valid,
-
1283 "ripple::NetworkOPsImp::processTransaction : valid validity");
-
1284
-
1285 // Not concerned with local checks at this point.
-
1286 if (validity == Validity::SigBad)
-
1287 {
-
1288 JLOG(m_journal.info()) << "Transaction has bad signature: " << reason;
-
1289 transaction->setStatus(INVALID);
-
1290 transaction->setResult(temBAD_SIGNATURE);
-
1291 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
-
1292 return false;
-
1293 }
-
1294
-
1295 // canonicalize can change our pointer
-
1296 app_.getMasterTransaction().canonicalize(&transaction);
-
1297
-
1298 return true;
-
1299}
-
1300
-
1301void
-
1302NetworkOPsImp::processTransaction(
-
1303 std::shared_ptr<Transaction>& transaction,
-
1304 bool bUnlimited,
-
1305 bool bLocal,
-
1306 FailHard failType)
-
1307{
-
1308 auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXN");
-
1309
-
1310 // preProcessTransaction can change our pointer
-
1311 if (!preProcessTransaction(transaction))
-
1312 return;
-
1313
-
1314 if (bLocal)
-
1315 doTransactionSync(transaction, bUnlimited, failType);
-
1316 else
-
1317 doTransactionAsync(transaction, bUnlimited, failType);
-
1318}
-
1319
-
1320void
-
1321NetworkOPsImp::doTransactionAsync(
-
1322 std::shared_ptr<Transaction> transaction,
-
1323 bool bUnlimited,
-
1324 FailHard failType)
-
1325{
-
1326 std::lock_guard lock(mMutex);
-
1327
-
1328 if (transaction->getApplying())
-
1329 return;
-
1330
-
1331 mTransactions.push_back(
-
1332 TransactionStatus(transaction, bUnlimited, false, failType));
-
1333 transaction->setApplying();
-
1334
-
1335 if (mDispatchState == DispatchState::none)
-
1336 {
-
1337 if (m_job_queue.addJob(
-
1338 jtBATCH, "transactionBatch", [this]() { transactionBatch(); }))
-
1339 {
-
1340 mDispatchState = DispatchState::scheduled;
-
1341 }
-
1342 }
-
1343}
-
1344
-
1345void
-
1346NetworkOPsImp::doTransactionSync(
-
1347 std::shared_ptr<Transaction> transaction,
-
1348 bool bUnlimited,
-
1349 FailHard failType)
-
1350{
-
1351 std::unique_lock<std::mutex> lock(mMutex);
-
1352
-
1353 if (!transaction->getApplying())
-
1354 {
-
1355 mTransactions.push_back(
-
1356 TransactionStatus(transaction, bUnlimited, true, failType));
-
1357 transaction->setApplying();
-
1358 }
-
1359
-
1360 doTransactionSyncBatch(
-
1361 lock, [&transaction](std::unique_lock<std::mutex> const&) {
-
1362 return transaction->getApplying();
-
1363 });
-
1364}
-
1365
-
1366void
-
1367NetworkOPsImp::doTransactionSyncBatch(
-
1368 std::unique_lock<std::mutex>& lock,
-
1369 std::function<bool(std::unique_lock<std::mutex> const&)> retryCallback)
-
1370{
-
1371 do
-
1372 {
-
1373 if (mDispatchState == DispatchState::running)
-
1374 {
-
1375 // A batch processing job is already running, so wait.
-
1376 mCond.wait(lock);
-
1377 }
-
1378 else
-
1379 {
-
1380 apply(lock);
-
1381
-
1382 if (mTransactions.size())
-
1383 {
-
1384 // More transactions need to be applied, but by another job.
-
1385 if (m_job_queue.addJob(jtBATCH, "transactionBatch", [this]() {
-
1386 transactionBatch();
-
1387 }))
-
1388 {
-
1389 mDispatchState = DispatchState::scheduled;
-
1390 }
-
1391 }
-
1392 }
-
1393 } while (retryCallback(lock));
-
1394}
-
1395
-
1396void
-
1397NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set)
-
1398{
-
1399 auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXNSet");
-
1400 std::vector<std::shared_ptr<Transaction>> candidates;
-
1401 candidates.reserve(set.size());
-
1402 for (auto const& [_, tx] : set)
-
1403 {
-
1404 std::string reason;
-
1405 auto transaction = std::make_shared<Transaction>(tx, reason, app_);
-
1406
-
1407 if (transaction->getStatus() == INVALID)
-
1408 {
-
1409 if (!reason.empty())
-
1410 {
-
1411 JLOG(m_journal.trace())
-
1412 << "Exception checking transaction: " << reason;
-
1413 }
-
1414 app_.getHashRouter().setFlags(tx->getTransactionID(), SF_BAD);
-
1415 continue;
-
1416 }
-
1417
-
1418 // preProcessTransaction can change our pointer
-
1419 if (!preProcessTransaction(transaction))
-
1420 continue;
-
1421
-
1422 candidates.emplace_back(transaction);
-
1423 }
-
1424
-
1425 std::vector<TransactionStatus> transactions;
-
1426 transactions.reserve(candidates.size());
-
1427
-
1428 std::unique_lock lock(mMutex);
-
1429
-
1430 for (auto& transaction : candidates)
-
1431 {
-
1432 if (!transaction->getApplying())
-
1433 {
-
1434 transactions.emplace_back(transaction, false, false, FailHard::no);
-
1435 transaction->setApplying();
-
1436 }
-
1437 }
-
1438
-
1439 if (mTransactions.empty())
-
1440 mTransactions.swap(transactions);
-
1441 else
-
1442 {
-
1443 mTransactions.reserve(mTransactions.size() + transactions.size());
-
1444 for (auto& t : transactions)
-
1445 mTransactions.push_back(std::move(t));
-
1446 }
-
1447
-
1448 doTransactionSyncBatch(lock, [&](std::unique_lock<std::mutex> const&) {
-
1449 XRPL_ASSERT(
-
1450 lock.owns_lock(),
-
1451 "ripple::NetworkOPsImp::processTransactionSet has lock");
-
1452 return std::any_of(
-
1453 mTransactions.begin(), mTransactions.end(), [](auto const& t) {
-
1454 return t.transaction->getApplying();
-
1455 });
-
1456 });
-
1457}
-
1458
-
1459void
-
1460NetworkOPsImp::transactionBatch()
-
1461{
-
1462 std::unique_lock<std::mutex> lock(mMutex);
-
1463
-
1464 if (mDispatchState == DispatchState::running)
-
1465 return;
-
1466
-
1467 while (mTransactions.size())
-
1468 {
-
1469 apply(lock);
-
1470 }
-
1471}
-
1472
-
1473void
-
1474NetworkOPsImp::apply(std::unique_lock<std::mutex>& batchLock)
-
1475{
-
1476 std::vector<TransactionStatus> submit_held;
-
1477 std::vector<TransactionStatus> transactions;
-
1478 mTransactions.swap(transactions);
-
1479 XRPL_ASSERT(
-
1480 !transactions.empty(),
-
1481 "ripple::NetworkOPsImp::apply : non-empty transactions");
-
1482 XRPL_ASSERT(
-
1483 mDispatchState != DispatchState::running,
-
1484 "ripple::NetworkOPsImp::apply : is not running");
-
1485
-
1486 mDispatchState = DispatchState::running;
-
1487
-
1488 batchLock.unlock();
-
1489
-
1490 {
-
1491 std::unique_lock masterLock{app_.getMasterMutex(), std::defer_lock};
-
1492 bool changed = false;
-
1493 {
-
1494 std::unique_lock ledgerLock{
-
1495 m_ledgerMaster.peekMutex(), std::defer_lock};
-
1496 std::lock(masterLock, ledgerLock);
-
1497
-
1498 app_.openLedger().modify([&](OpenView& view, beast::Journal j) {
-
1499 for (TransactionStatus& e : transactions)
-
1500 {
-
1501 // we check before adding to the batch
-
1502 ApplyFlags flags = tapNONE;
-
1503 if (e.admin)
-
1504 flags |= tapUNLIMITED;
-
1505
-
1506 if (e.failType == FailHard::yes)
-
1507 flags |= tapFAIL_HARD;
-
1508
-
1509 auto const result = app_.getTxQ().apply(
-
1510 app_, view, e.transaction->getSTransaction(), flags, j);
-
1511 e.result = result.ter;
-
1512 e.applied = result.applied;
-
1513 changed = changed || result.applied;
-
1514 }
-
1515 return changed;
-
1516 });
-
1517 }
-
1518 if (changed)
-
1519 reportFeeChange();
-
1520
-
1521 std::optional<LedgerIndex> validatedLedgerIndex;
-
1522 if (auto const l = m_ledgerMaster.getValidatedLedger())
-
1523 validatedLedgerIndex = l->info().seq;
-
1524
-
1525 auto newOL = app_.openLedger().current();
-
1526 for (TransactionStatus& e : transactions)
-
1527 {
-
1528 e.transaction->clearSubmitResult();
-
1529
-
1530 if (e.applied)
-
1531 {
-
1532 pubProposedTransaction(
-
1533 newOL, e.transaction->getSTransaction(), e.result);
-
1534 e.transaction->setApplied();
-
1535 }
-
1536
-
1537 e.transaction->setResult(e.result);
-
1538
-
1539 if (isTemMalformed(e.result))
-
1540 app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
-
1541
-
1542#ifdef DEBUG
-
1543 if (e.result != tesSUCCESS)
-
1544 {
-
1545 std::string token, human;
-
1546
-
1547 if (transResultInfo(e.result, token, human))
-
1548 {
-
1549 JLOG(m_journal.info())
-
1550 << "TransactionResult: " << token << ": " << human;
-
1551 }
-
1552 }
-
1553#endif
-
1554
-
1555 bool addLocal = e.local;
-
1556
-
1557 if (e.result == tesSUCCESS)
-
1558 {
-
1559 JLOG(m_journal.debug())
-
1560 << "Transaction is now included in open ledger";
-
1561 e.transaction->setStatus(INCLUDED);
-
1562
-
1563 // Pop as many "reasonable" transactions for this account as
-
1564 // possible. "Reasonable" means they have sequential sequence
-
1565 // numbers, or use tickets.
-
1566 auto const& txCur = e.transaction->getSTransaction();
-
1567
-
1568 std::size_t count = 0;
-
1569 for (auto txNext = m_ledgerMaster.popAcctTransaction(txCur);
-
1570 txNext && count < maxPoppedTransactions;
-
1571 txNext = m_ledgerMaster.popAcctTransaction(txCur), ++count)
-
1572 {
-
1573 if (!batchLock.owns_lock())
-
1574 batchLock.lock();
-
1575 std::string reason;
-
1576 auto const trans = sterilize(*txNext);
-
1577 auto t = std::make_shared<Transaction>(trans, reason, app_);
-
1578 if (t->getApplying())
-
1579 break;
-
1580 submit_held.emplace_back(t, false, false, FailHard::no);
-
1581 t->setApplying();
-
1582 }
-
1583 if (batchLock.owns_lock())
-
1584 batchLock.unlock();
-
1585 }
-
1586 else if (e.result == tefPAST_SEQ)
-
1587 {
-
1588 // duplicate or conflict
-
1589 JLOG(m_journal.info()) << "Transaction is obsolete";
-
1590 e.transaction->setStatus(OBSOLETE);
-
1591 }
-
1592 else if (e.result == terQUEUED)
-
1593 {
-
1594 JLOG(m_journal.debug())
-
1595 << "Transaction is likely to claim a"
-
1596 << " fee, but is queued until fee drops";
-
1597
-
1598 e.transaction->setStatus(HELD);
-
1599 // Add to held transactions, because it could get
-
1600 // kicked out of the queue, and this will try to
-
1601 // put it back.
-
1602 m_ledgerMaster.addHeldTransaction(e.transaction);
-
1603 e.transaction->setQueued();
-
1604 e.transaction->setKept();
-
1605 }
-
1606 else if (
-
1607 isTerRetry(e.result) || isTelLocal(e.result) ||
-
1608 isTefFailure(e.result))
-
1609 {
-
1610 if (e.failType != FailHard::yes)
-
1611 {
-
1612 auto const lastLedgerSeq =
-
1613 e.transaction->getSTransaction()->at(
-
1614 ~sfLastLedgerSequence);
-
1615 auto const ledgersLeft = lastLedgerSeq
-
1616 ? *lastLedgerSeq -
-
1617 m_ledgerMaster.getCurrentLedgerIndex()
-
1618 : std::optional<LedgerIndex>{};
-
1619 // If any of these conditions are met, the transaction can
-
1620 // be held:
-
1621 // 1. It was submitted locally. (Note that this flag is only
-
1622 // true on the initial submission.)
-
1623 // 2. The transaction has a LastLedgerSequence, and the
-
1624 // LastLedgerSequence is fewer than LocalTxs::holdLedgers
-
1625 // (5) ledgers into the future. (Remember that an
-
1626 // unseated optional compares as less than all seated
-
1627 // values, so it has to be checked explicitly first.)
-
1628 // 3. The SF_HELD flag is not set on the txID. (setFlags
-
1629 // checks before setting. If the flag is set, it returns
-
1630 // false, which means it's been held once without one of
-
1631 // the other conditions, so don't hold it again. Time's
-
1632 // up!)
-
1633 //
-
1634 if (e.local ||
-
1635 (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) ||
-
1636 app_.getHashRouter().setFlags(
-
1637 e.transaction->getID(), SF_HELD))
-
1638 {
-
1639 // transaction should be held
-
1640 JLOG(m_journal.debug())
-
1641 << "Transaction should be held: " << e.result;
-
1642 e.transaction->setStatus(HELD);
-
1643 m_ledgerMaster.addHeldTransaction(e.transaction);
-
1644 e.transaction->setKept();
-
1645 }
-
1646 else
-
1647 JLOG(m_journal.debug())
-
1648 << "Not holding transaction "
-
1649 << e.transaction->getID() << ": "
-
1650 << (e.local ? "local" : "network") << ", "
-
1651 << "result: " << e.result << " ledgers left: "
-
1652 << (ledgersLeft ? to_string(*ledgersLeft)
-
1653 : "unspecified");
-
1654 }
-
1655 }
-
1656 else
-
1657 {
-
1658 JLOG(m_journal.debug())
-
1659 << "Status other than success " << e.result;
-
1660 e.transaction->setStatus(INVALID);
-
1661 }
-
1662
-
1663 auto const enforceFailHard =
-
1664 e.failType == FailHard::yes && !isTesSuccess(e.result);
-
1665
-
1666 if (addLocal && !enforceFailHard)
-
1667 {
-
1668 m_localTX->push_back(
-
1669 m_ledgerMaster.getCurrentLedgerIndex(),
-
1670 e.transaction->getSTransaction());
-
1671 e.transaction->setKept();
-
1672 }
-
1673
-
1674 if ((e.applied ||
-
1675 ((mMode != OperatingMode::FULL) &&
-
1676 (e.failType != FailHard::yes) && e.local) ||
-
1677 (e.result == terQUEUED)) &&
-
1678 !enforceFailHard)
-
1679 {
-
1680 auto const toSkip =
-
1681 app_.getHashRouter().shouldRelay(e.transaction->getID());
-
1682 if (auto const sttx = *(e.transaction->getSTransaction());
-
1683 toSkip &&
-
1684 // Skip relaying if it's an inner batch txn and batch
-
1685 // feature is enabled
-
1686 !(sttx.isFlag(tfInnerBatchTxn) &&
-
1687 newOL->rules().enabled(featureBatch)))
-
1688 {
-
1689 protocol::TMTransaction tx;
-
1690 Serializer s;
-
1691
-
1692 sttx.add(s);
-
1693 tx.set_rawtransaction(s.data(), s.size());
-
1694 tx.set_status(protocol::tsCURRENT);
-
1695 tx.set_receivetimestamp(
-
1696 app_.timeKeeper().now().time_since_epoch().count());
-
1697 tx.set_deferred(e.result == terQUEUED);
-
1698 // FIXME: This should be when we received it
-
1699 app_.overlay().relay(e.transaction->getID(), tx, *toSkip);
-
1700 e.transaction->setBroadcast();
-
1701 }
-
1702 }
-
1703
-
1704 if (validatedLedgerIndex)
-
1705 {
-
1706 auto [fee, accountSeq, availableSeq] =
-
1707 app_.getTxQ().getTxRequiredFeeAndSeq(
-
1708 *newOL, e.transaction->getSTransaction());
-
1709 e.transaction->setCurrentLedgerState(
-
1710 *validatedLedgerIndex, fee, accountSeq, availableSeq);
-
1711 }
-
1712 }
-
1713 }
-
1714
-
1715 batchLock.lock();
-
1716
-
1717 for (TransactionStatus& e : transactions)
-
1718 e.transaction->clearApplying();
-
1719
-
1720 if (!submit_held.empty())
-
1721 {
-
1722 if (mTransactions.empty())
-
1723 mTransactions.swap(submit_held);
-
1724 else
-
1725 {
-
1726 mTransactions.reserve(mTransactions.size() + submit_held.size());
-
1727 for (auto& e : submit_held)
-
1728 mTransactions.push_back(std::move(e));
-
1729 }
-
1730 }
-
1731
-
1732 mCond.notify_all();
-
1733
-
1734 mDispatchState = DispatchState::none;
-
1735}
-
1736
-
1737//
-
1738// Owner functions
-
1739//
-
1740
-
1741Json::Value
-
1742NetworkOPsImp::getOwnerInfo(
-
1743 std::shared_ptr<ReadView const> lpLedger,
-
1744 AccountID const& account)
-
1745{
-
1746 Json::Value jvObjects(Json::objectValue);
-
1747 auto root = keylet::ownerDir(account);
-
1748 auto sleNode = lpLedger->read(keylet::page(root));
-
1749 if (sleNode)
-
1750 {
-
1751 std::uint64_t uNodeDir;
-
1752
-
1753 do
-
1754 {
-
1755 for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
-
1756 {
-
1757 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
-
1758 XRPL_ASSERT(
-
1759 sleCur,
-
1760 "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE");
-
1761
-
1762 switch (sleCur->getType())
-
1763 {
-
1764 case ltOFFER:
-
1765 if (!jvObjects.isMember(jss::offers))
-
1766 jvObjects[jss::offers] =
-
1767 Json::Value(Json::arrayValue);
-
1768
-
1769 jvObjects[jss::offers].append(
-
1770 sleCur->getJson(JsonOptions::none));
-
1771 break;
-
1772
-
1773 case ltRIPPLE_STATE:
-
1774 if (!jvObjects.isMember(jss::ripple_lines))
-
1775 {
-
1776 jvObjects[jss::ripple_lines] =
-
1777 Json::Value(Json::arrayValue);
-
1778 }
-
1779
-
1780 jvObjects[jss::ripple_lines].append(
-
1781 sleCur->getJson(JsonOptions::none));
-
1782 break;
-
1783
-
1784 case ltACCOUNT_ROOT:
-
1785 case ltDIR_NODE:
-
1786 default:
-
1787 UNREACHABLE(
-
1788 "ripple::NetworkOPsImp::getOwnerInfo : invalid "
-
1789 "type");
-
1790 break;
-
1791 }
-
1792 }
-
1793
-
1794 uNodeDir = sleNode->getFieldU64(sfIndexNext);
-
1795
-
1796 if (uNodeDir)
-
1797 {
-
1798 sleNode = lpLedger->read(keylet::page(root, uNodeDir));
-
1799 XRPL_ASSERT(
-
1800 sleNode,
-
1801 "ripple::NetworkOPsImp::getOwnerInfo : read next page");
-
1802 }
-
1803 } while (uNodeDir);
-
1804 }
-
1805
-
1806 return jvObjects;
-
1807}
-
1808
-
1809//
-
1810// Other
-
1811//
-
1812
-
1813inline bool
-
1814NetworkOPsImp::isBlocked()
-
1815{
-
1816 return isAmendmentBlocked() || isUNLBlocked();
-
1817}
-
1818
-
1819inline bool
-
1820NetworkOPsImp::isAmendmentBlocked()
-
1821{
-
1822 return amendmentBlocked_;
-
1823}
-
1824
-
1825void
-
1826NetworkOPsImp::setAmendmentBlocked()
-
1827{
-
1828 amendmentBlocked_ = true;
-
1829 setMode(OperatingMode::CONNECTED);
-
1830}
-
1831
-
1832inline bool
-
1833NetworkOPsImp::isAmendmentWarned()
-
1834{
-
1835 return !amendmentBlocked_ && amendmentWarned_;
-
1836}
-
1837
-
1838inline void
-
1839NetworkOPsImp::setAmendmentWarned()
-
1840{
-
1841 amendmentWarned_ = true;
-
1842}
-
1843
-
1844inline void
-
1845NetworkOPsImp::clearAmendmentWarned()
-
1846{
-
1847 amendmentWarned_ = false;
-
1848}
-
1849
-
1850inline bool
-
1851NetworkOPsImp::isUNLBlocked()
-
1852{
-
1853 return unlBlocked_;
-
1854}
-
1855
-
1856void
-
1857NetworkOPsImp::setUNLBlocked()
-
1858{
-
1859 unlBlocked_ = true;
-
1860 setMode(OperatingMode::CONNECTED);
-
1861}
-
1862
-
1863inline void
-
1864NetworkOPsImp::clearUNLBlocked()
-
1865{
-
1866 unlBlocked_ = false;
-
1867}
-
1868
-
1869bool
-
1870NetworkOPsImp::checkLastClosedLedger(
-
1871 Overlay::PeerSequence const& peerList,
-
1872 uint256& networkClosed)
-
1873{
-
1874 // Returns true if there's an *abnormal* ledger issue, normal changing in
-
1875 // TRACKING mode should return false. Do we have sufficient validations for
-
1876 // our last closed ledger? Or do sufficient nodes agree? And do we have no
-
1877 // better ledger available? If so, we are either tracking or full.
-
1878
-
1879 JLOG(m_journal.trace()) << "NetworkOPsImp::checkLastClosedLedger";
-
1880
-
1881 auto const ourClosed = m_ledgerMaster.getClosedLedger();
-
1882
-
1883 if (!ourClosed)
-
1884 return false;
-
1885
-
1886 uint256 closedLedger = ourClosed->info().hash;
-
1887 uint256 prevClosedLedger = ourClosed->info().parentHash;
-
1888 JLOG(m_journal.trace()) << "OurClosed: " << closedLedger;
-
1889 JLOG(m_journal.trace()) << "PrevClosed: " << prevClosedLedger;
-
1890
-
1891 //-------------------------------------------------------------------------
-
1892 // Determine preferred last closed ledger
-
1893
-
1894 auto& validations = app_.getValidations();
-
1895 JLOG(m_journal.debug())
-
1896 << "ValidationTrie " << Json::Compact(validations.getJsonTrie());
-
1897
-
1898 // Will rely on peer LCL if no trusted validations exist
-
1899 hash_map<uint256, std::uint32_t> peerCounts;
-
1900 peerCounts[closedLedger] = 0;
-
1901 if (mMode >= OperatingMode::TRACKING)
-
1902 peerCounts[closedLedger]++;
-
1903
-
1904 for (auto& peer : peerList)
-
1905 {
-
1906 uint256 peerLedger = peer->getClosedLedgerHash();
-
1907
-
1908 if (peerLedger.isNonZero())
-
1909 ++peerCounts[peerLedger];
-
1910 }
-
1911
-
1912 for (auto const& it : peerCounts)
-
1913 JLOG(m_journal.debug()) << "L: " << it.first << " n=" << it.second;
-
1914
-
1915 uint256 preferredLCL = validations.getPreferredLCL(
-
1916 RCLValidatedLedger{ourClosed, validations.adaptor().journal()},
-
1917 m_ledgerMaster.getValidLedgerIndex(),
-
1918 peerCounts);
-
1919
-
1920 bool switchLedgers = preferredLCL != closedLedger;
-
1921 if (switchLedgers)
-
1922 closedLedger = preferredLCL;
-
1923 //-------------------------------------------------------------------------
-
1924 if (switchLedgers && (closedLedger == prevClosedLedger))
-
1925 {
-
1926 // don't switch to our own previous ledger
-
1927 JLOG(m_journal.info()) << "We won't switch to our own previous ledger";
-
1928 networkClosed = ourClosed->info().hash;
-
1929 switchLedgers = false;
-
1930 }
-
1931 else
-
1932 networkClosed = closedLedger;
-
1933
-
1934 if (!switchLedgers)
-
1935 return false;
-
1936
-
1937 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
-
1938
-
1939 if (!consensus)
-
1940 consensus = app_.getInboundLedgers().acquire(
-
1941 closedLedger, 0, InboundLedger::Reason::CONSENSUS);
-
1942
-
1943 if (consensus &&
-
1944 (!m_ledgerMaster.canBeCurrent(consensus) ||
-
1945 !m_ledgerMaster.isCompatible(
-
1946 *consensus, m_journal.debug(), "Not switching")))
-
1947 {
-
1948 // Don't switch to a ledger not on the validated chain
-
1949 // or with an invalid close time or sequence
-
1950 networkClosed = ourClosed->info().hash;
-
1951 return false;
-
1952 }
-
1953
-
1954 JLOG(m_journal.warn()) << "We are not running on the consensus ledger";
-
1955 JLOG(m_journal.info()) << "Our LCL: " << ourClosed->info().hash
-
1956 << getJson({*ourClosed, {}});
-
1957 JLOG(m_journal.info()) << "Net LCL " << closedLedger;
-
1958
-
1959 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
-
1960 {
-
1961 setMode(OperatingMode::CONNECTED);
-
1962 }
-
1963
-
1964 if (consensus)
-
1965 {
-
1966 // FIXME: If this rewinds the ledger sequence, or has the same
-
1967 // sequence, we should update the status on any stored transactions
-
1968 // in the invalidated ledgers.
-
1969 switchLastClosedLedger(consensus);
-
1970 }
-
1971
-
1972 return true;
-
1973}
-
1974
-
1975void
-
1976NetworkOPsImp::switchLastClosedLedger(
-
1977 std::shared_ptr<Ledger const> const& newLCL)
-
1978{
-
1979 // set the newLCL as our last closed ledger -- this is abnormal code
-
1980 JLOG(m_journal.error())
-
1981 << "JUMP last closed ledger to " << newLCL->info().hash;
-
1982
-
1983 clearNeedNetworkLedger();
-
1984
-
1985 // Update fee computations.
-
1986 app_.getTxQ().processClosedLedger(app_, *newLCL, true);
-
1987
-
1988 // Caller must own master lock
-
1989 {
-
1990 // Apply tx in old open ledger to new
-
1991 // open ledger. Then apply local tx.
-
1992
-
1993 auto retries = m_localTX->getTxSet();
-
1994 auto const lastVal = app_.getLedgerMaster().getValidatedLedger();
-
1995 std::optional<Rules> rules;
-
1996 if (lastVal)
-
1997 rules = makeRulesGivenLedger(*lastVal, app_.config().features);
-
1998 else
-
1999 rules.emplace(app_.config().features);
-
2000 app_.openLedger().accept(
-
2001 app_,
-
2002 *rules,
-
2003 newLCL,
-
2004 OrderedTxs({}),
-
2005 false,
-
2006 retries,
-
2007 tapNONE,
-
2008 "jump",
-
2009 [&](OpenView& view, beast::Journal j) {
-
2010 // Stuff the ledger with transactions from the queue.
-
2011 return app_.getTxQ().accept(app_, view);
-
2012 });
-
2013 }
-
2014
-
2015 m_ledgerMaster.switchLCL(newLCL);
-
2016
-
2017 protocol::TMStatusChange s;
-
2018 s.set_newevent(protocol::neSWITCHED_LEDGER);
-
2019 s.set_ledgerseq(newLCL->info().seq);
-
2020 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
-
2021 s.set_ledgerhashprevious(
-
2022 newLCL->info().parentHash.begin(), newLCL->info().parentHash.size());
-
2023 s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size());
-
2024
-
2025 app_.overlay().foreach(
-
2026 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
-
2027}
-
2028
-
2029bool
-
2030NetworkOPsImp::beginConsensus(
-
2031 uint256 const& networkClosed,
-
2032 std::unique_ptr<std::stringstream> const& clog)
-
2033{
-
2034 XRPL_ASSERT(
-
2035 networkClosed.isNonZero(),
-
2036 "ripple::NetworkOPsImp::beginConsensus : nonzero input");
-
2037
-
2038 auto closingInfo = m_ledgerMaster.getCurrentLedger()->info();
-
2039
-
2040 JLOG(m_journal.info()) << "Consensus time for #" << closingInfo.seq
-
2041 << " with LCL " << closingInfo.parentHash;
-
2042
-
2043 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
-
2044
-
2045 if (!prevLedger)
-
2046 {
-
2047 // this shouldn't happen unless we jump ledgers
-
2048 if (mMode == OperatingMode::FULL)
-
2049 {
-
2050 JLOG(m_journal.warn()) << "Don't have LCL, going to tracking";
-
2051 setMode(OperatingMode::TRACKING);
-
2052 CLOG(clog) << "beginConsensus Don't have LCL, going to tracking. ";
-
2053 }
-
2054
-
2055 CLOG(clog) << "beginConsensus no previous ledger. ";
-
2056 return false;
-
2057 }
-
2058
-
2059 XRPL_ASSERT(
-
2060 prevLedger->info().hash == closingInfo.parentHash,
-
2061 "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches "
-
2062 "parent");
-
2063 XRPL_ASSERT(
-
2064 closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash,
-
2065 "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches "
-
2066 "hash");
-
2067
-
2068 if (prevLedger->rules().enabled(featureNegativeUNL))
-
2069 app_.validators().setNegativeUNL(prevLedger->negativeUNL());
-
2070 TrustChanges const changes = app_.validators().updateTrusted(
-
2071 app_.getValidations().getCurrentNodeIDs(),
-
2072 closingInfo.parentCloseTime,
-
2073 *this,
-
2074 app_.overlay(),
-
2075 app_.getHashRouter());
-
2076
-
2077 if (!changes.added.empty() || !changes.removed.empty())
-
2078 {
-
2079 app_.getValidations().trustChanged(changes.added, changes.removed);
-
2080 // Update the AmendmentTable so it tracks the current validators.
-
2081 app_.getAmendmentTable().trustChanged(
-
2082 app_.validators().getQuorumKeys().second);
-
2083 }
-
2084
-
2085 mConsensus.startRound(
-
2086 app_.timeKeeper().closeTime(),
-
2087 networkClosed,
-
2088 prevLedger,
-
2089 changes.removed,
-
2090 changes.added,
-
2091 clog);
-
2092
-
2093 ConsensusPhase const currPhase = mConsensus.phase();
-
2094 if (mLastConsensusPhase != currPhase)
-
2095 {
-
2096 reportConsensusStateChange(currPhase);
-
2097 mLastConsensusPhase = currPhase;
-
2098 }
-
2099
-
2100 JLOG(m_journal.debug()) << "Initiating consensus engine";
-
2101 return true;
-
2102}
-
2103
-
2104bool
-
2105NetworkOPsImp::processTrustedProposal(RCLCxPeerPos peerPos)
-
2106{
-
2107 auto const& peerKey = peerPos.publicKey();
-
2108 if (validatorPK_ == peerKey || validatorMasterPK_ == peerKey)
-
2109 {
-
2110 // Could indicate a operator misconfiguration where two nodes are
-
2111 // running with the same validator key configured, so this isn't fatal,
-
2112 // and it doesn't necessarily indicate peer misbehavior. But since this
-
2113 // is a trusted message, it could be a very big deal. Either way, we
-
2114 // don't want to relay the proposal. Note that the byzantine behavior
-
2115 // detection in handleNewValidation will notify other peers.
-
2116 //
-
2117 // Another, innocuous explanation is unusual message routing and delays,
-
2118 // causing this node to receive its own messages back.
-
2119 JLOG(m_journal.error())
-
2120 << "Received a proposal signed by MY KEY from a peer. This may "
-
2121 "indicate a misconfiguration where another node has the same "
-
2122 "validator key, or may be caused by unusual message routing and "
-
2123 "delays.";
-
2124 return false;
-
2125 }
-
2126
-
2127 return mConsensus.peerProposal(app_.timeKeeper().closeTime(), peerPos);
-
2128}
-
2129
-
2130void
-
2131NetworkOPsImp::mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire)
-
2132{
-
2133 // We now have an additional transaction set
-
2134 // either created locally during the consensus process
-
2135 // or acquired from a peer
-
2136
-
2137 // Inform peers we have this set
-
2138 protocol::TMHaveTransactionSet msg;
-
2139 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
-
2140 msg.set_status(protocol::tsHAVE);
-
2141 app_.overlay().foreach(
-
2142 send_always(std::make_shared<Message>(msg, protocol::mtHAVE_SET)));
-
2143
-
2144 // We acquired it because consensus asked us to
-
2145 if (fromAcquire)
-
2146 mConsensus.gotTxSet(app_.timeKeeper().closeTime(), RCLTxSet{map});
-
2147}
-
2148
-
2149void
-
2150NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
-
2151{
-
2152 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash;
-
2153
-
2154 for (auto const& it : app_.overlay().getActivePeers())
-
2155 {
-
2156 if (it && (it->getClosedLedgerHash() == deadLedger))
-
2157 {
-
2158 JLOG(m_journal.trace()) << "Killing obsolete peer status";
-
2159 it->cycleStatus();
-
2160 }
-
2161 }
-
2162
-
2163 uint256 networkClosed;
-
2164 bool ledgerChange =
-
2165 checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed);
-
2166
-
2167 if (networkClosed.isZero())
-
2168 {
-
2169 CLOG(clog) << "endConsensus last closed ledger is zero. ";
-
2170 return;
-
2171 }
-
2172
-
2173 // WRITEME: Unless we are in FULL and in the process of doing a consensus,
-
2174 // we must count how many nodes share our LCL, how many nodes disagree with
-
2175 // our LCL, and how many validations our LCL has. We also want to check
-
2176 // timing to make sure there shouldn't be a newer LCL. We need this
-
2177 // information to do the next three tests.
-
2178
-
2179 if (((mMode == OperatingMode::CONNECTED) ||
-
2180 (mMode == OperatingMode::SYNCING)) &&
-
2181 !ledgerChange)
-
2182 {
-
2183 // Count number of peers that agree with us and UNL nodes whose
-
2184 // validations we have for LCL. If the ledger is good enough, go to
-
2185 // TRACKING - TODO
-
2186 if (!needNetworkLedger_)
-
2187 setMode(OperatingMode::TRACKING);
-
2188 }
-
2189
-
2190 if (((mMode == OperatingMode::CONNECTED) ||
-
2191 (mMode == OperatingMode::TRACKING)) &&
-
2192 !ledgerChange)
-
2193 {
-
2194 // check if the ledger is good enough to go to FULL
-
2195 // Note: Do not go to FULL if we don't have the previous ledger
-
2196 // check if the ledger is bad enough to go to CONNECTE D -- TODO
-
2197 auto current = m_ledgerMaster.getCurrentLedger();
-
2198 if (app_.timeKeeper().now() < (current->info().parentCloseTime +
-
2199 2 * current->info().closeTimeResolution))
-
2200 {
-
2201 setMode(OperatingMode::FULL);
-
2202 }
-
2203 }
-
2204
-
2205 beginConsensus(networkClosed, clog);
-
2206}
-
2207
-
2208void
-
2209NetworkOPsImp::consensusViewChange()
-
2210{
-
2211 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
-
2212 {
-
2213 setMode(OperatingMode::CONNECTED);
-
2214 }
-
2215}
-
2216
-
2217void
-
2218NetworkOPsImp::pubManifest(Manifest const& mo)
-
2219{
-
2220 // VFALCO consider std::shared_mutex
-
2221 std::lock_guard sl(mSubLock);
-
2222
-
2223 if (!mStreamMaps[sManifests].empty())
-
2224 {
-
2225 Json::Value jvObj(Json::objectValue);
-
2226
-
2227 jvObj[jss::type] = "manifestReceived";
-
2228 jvObj[jss::master_key] = toBase58(TokenType::NodePublic, mo.masterKey);
-
2229 if (mo.signingKey)
-
2230 jvObj[jss::signing_key] =
-
2231 toBase58(TokenType::NodePublic, *mo.signingKey);
-
2232 jvObj[jss::seq] = Json::UInt(mo.sequence);
-
2233 if (auto sig = mo.getSignature())
-
2234 jvObj[jss::signature] = strHex(*sig);
-
2235 jvObj[jss::master_signature] = strHex(mo.getMasterSignature());
-
2236 if (!mo.domain.empty())
-
2237 jvObj[jss::domain] = mo.domain;
-
2238 jvObj[jss::manifest] = strHex(mo.serialized);
-
2239
-
2240 for (auto i = mStreamMaps[sManifests].begin();
-
2241 i != mStreamMaps[sManifests].end();)
-
2242 {
-
2243 if (auto p = i->second.lock())
-
2244 {
-
2245 p->send(jvObj, true);
-
2246 ++i;
-
2247 }
-
2248 else
-
2249 {
-
2250 i = mStreamMaps[sManifests].erase(i);
-
2251 }
-
2252 }
-
2253 }
-
2254}
-
2255
-
2256NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
-
2257 XRPAmount fee,
-
2258 TxQ::Metrics&& escalationMetrics,
-
2259 LoadFeeTrack const& loadFeeTrack)
-
2260 : loadFactorServer{loadFeeTrack.getLoadFactor()}
-
2261 , loadBaseServer{loadFeeTrack.getLoadBase()}
-
2262 , baseFee{fee}
-
2263 , em{std::move(escalationMetrics)}
-
2264{
-
2265}
-
2266
-
2267bool
-
2268NetworkOPsImp::ServerFeeSummary::operator!=(
-
2269 NetworkOPsImp::ServerFeeSummary const& b) const
-
2270{
-
2271 if (loadFactorServer != b.loadFactorServer ||
-
2272 loadBaseServer != b.loadBaseServer || baseFee != b.baseFee ||
-
2273 em.has_value() != b.em.has_value())
-
2274 return true;
-
2275
-
2276 if (em && b.em)
-
2277 {
-
2278 return (
-
2279 em->minProcessingFeeLevel != b.em->minProcessingFeeLevel ||
-
2280 em->openLedgerFeeLevel != b.em->openLedgerFeeLevel ||
-
2281 em->referenceFeeLevel != b.em->referenceFeeLevel);
-
2282 }
-
2283
-
2284 return false;
-
2285}
-
2286
-
2287// Need to cap to uint64 to uint32 due to JSON limitations
-
2288static std::uint32_t
-
2289trunc32(std::uint64_t v)
-
2290{
-
2291 constexpr std::uint64_t max32 = std::numeric_limits<std::uint32_t>::max();
-
2292
-
2293 return std::min(max32, v);
-
2294};
-
2295
-
2296void
-
2297NetworkOPsImp::pubServer()
-
2298{
-
2299 // VFALCO TODO Don't hold the lock across calls to send...make a copy of the
-
2300 // list into a local array while holding the lock then release
-
2301 // the lock and call send on everyone.
-
2302 //
-
2303 std::lock_guard sl(mSubLock);
-
2304
-
2305 if (!mStreamMaps[sServer].empty())
-
2306 {
-
2307 Json::Value jvObj(Json::objectValue);
-
2308
-
2309 ServerFeeSummary f{
-
2310 app_.openLedger().current()->fees().base,
-
2311 app_.getTxQ().getMetrics(*app_.openLedger().current()),
-
2312 app_.getFeeTrack()};
-
2313
-
2314 jvObj[jss::type] = "serverStatus";
-
2315 jvObj[jss::server_status] = strOperatingMode();
-
2316 jvObj[jss::load_base] = f.loadBaseServer;
-
2317 jvObj[jss::load_factor_server] = f.loadFactorServer;
-
2318 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
-
2319
-
2320 if (f.em)
-
2321 {
-
2322 auto const loadFactor = std::max(
-
2323 safe_cast<std::uint64_t>(f.loadFactorServer),
-
2324 mulDiv(
-
2325 f.em->openLedgerFeeLevel,
-
2326 f.loadBaseServer,
-
2327 f.em->referenceFeeLevel)
-
2328 .value_or(ripple::muldiv_max));
-
2329
-
2330 jvObj[jss::load_factor] = trunc32(loadFactor);
-
2331 jvObj[jss::load_factor_fee_escalation] =
-
2332 f.em->openLedgerFeeLevel.jsonClipped();
-
2333 jvObj[jss::load_factor_fee_queue] =
-
2334 f.em->minProcessingFeeLevel.jsonClipped();
-
2335 jvObj[jss::load_factor_fee_reference] =
-
2336 f.em->referenceFeeLevel.jsonClipped();
-
2337 }
-
2338 else
-
2339 jvObj[jss::load_factor] = f.loadFactorServer;
-
2340
-
2341 mLastFeeSummary = f;
-
2342
-
2343 for (auto i = mStreamMaps[sServer].begin();
-
2344 i != mStreamMaps[sServer].end();)
-
2345 {
-
2346 InfoSub::pointer p = i->second.lock();
-
2347
-
2348 // VFALCO TODO research the possibility of using thread queues and
-
2349 // linearizing the deletion of subscribers with the
-
2350 // sending of JSON data.
-
2351 if (p)
-
2352 {
-
2353 p->send(jvObj, true);
-
2354 ++i;
-
2355 }
-
2356 else
-
2357 {
-
2358 i = mStreamMaps[sServer].erase(i);
-
2359 }
-
2360 }
-
2361 }
-
2362}
-
2363
-
2364void
-
2365NetworkOPsImp::pubConsensus(ConsensusPhase phase)
-
2366{
-
2367 std::lock_guard sl(mSubLock);
-
2368
-
2369 auto& streamMap = mStreamMaps[sConsensusPhase];
-
2370 if (!streamMap.empty())
-
2371 {
-
2372 Json::Value jvObj(Json::objectValue);
-
2373 jvObj[jss::type] = "consensusPhase";
-
2374 jvObj[jss::consensus] = to_string(phase);
-
2375
-
2376 for (auto i = streamMap.begin(); i != streamMap.end();)
-
2377 {
-
2378 if (auto p = i->second.lock())
-
2379 {
-
2380 p->send(jvObj, true);
-
2381 ++i;
-
2382 }
-
2383 else
-
2384 {
-
2385 i = streamMap.erase(i);
-
2386 }
-
2387 }
-
2388 }
-
2389}
-
2390
-
2391void
-
2392NetworkOPsImp::pubValidation(std::shared_ptr<STValidation> const& val)
-
2393{
-
2394 // VFALCO consider std::shared_mutex
-
2395 std::lock_guard sl(mSubLock);
-
2396
-
2397 if (!mStreamMaps[sValidations].empty())
-
2398 {
-
2399 Json::Value jvObj(Json::objectValue);
-
2400
-
2401 auto const signerPublic = val->getSignerPublic();
-
2402
-
2403 jvObj[jss::type] = "validationReceived";
-
2404 jvObj[jss::validation_public_key] =
-
2405 toBase58(TokenType::NodePublic, signerPublic);
-
2406 jvObj[jss::ledger_hash] = to_string(val->getLedgerHash());
-
2407 jvObj[jss::signature] = strHex(val->getSignature());
-
2408 jvObj[jss::full] = val->isFull();
-
2409 jvObj[jss::flags] = val->getFlags();
-
2410 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
-
2411 jvObj[jss::data] = strHex(val->getSerializer().slice());
-
2412
-
2413 if (auto version = (*val)[~sfServerVersion])
-
2414 jvObj[jss::server_version] = std::to_string(*version);
-
2415
-
2416 if (auto cookie = (*val)[~sfCookie])
-
2417 jvObj[jss::cookie] = std::to_string(*cookie);
-
2418
-
2419 if (auto hash = (*val)[~sfValidatedHash])
-
2420 jvObj[jss::validated_hash] = strHex(*hash);
-
2421
-
2422 auto const masterKey =
-
2423 app_.validatorManifests().getMasterKey(signerPublic);
-
2424
-
2425 if (masterKey != signerPublic)
-
2426 jvObj[jss::master_key] = toBase58(TokenType::NodePublic, masterKey);
-
2427
-
2428 // NOTE *seq is a number, but old API versions used string. We replace
-
2429 // number with a string using MultiApiJson near end of this function
-
2430 if (auto const seq = (*val)[~sfLedgerSequence])
-
2431 jvObj[jss::ledger_index] = *seq;
-
2432
-
2433 if (val->isFieldPresent(sfAmendments))
-
2434 {
-
2435 jvObj[jss::amendments] = Json::Value(Json::arrayValue);
-
2436 for (auto const& amendment : val->getFieldV256(sfAmendments))
-
2437 jvObj[jss::amendments].append(to_string(amendment));
-
2438 }
-
2439
-
2440 if (auto const closeTime = (*val)[~sfCloseTime])
-
2441 jvObj[jss::close_time] = *closeTime;
-
2442
-
2443 if (auto const loadFee = (*val)[~sfLoadFee])
-
2444 jvObj[jss::load_fee] = *loadFee;
-
2445
-
2446 if (auto const baseFee = val->at(~sfBaseFee))
-
2447 jvObj[jss::base_fee] = static_cast<double>(*baseFee);
-
2448
-
2449 if (auto const reserveBase = val->at(~sfReserveBase))
-
2450 jvObj[jss::reserve_base] = *reserveBase;
-
2451
-
2452 if (auto const reserveInc = val->at(~sfReserveIncrement))
-
2453 jvObj[jss::reserve_inc] = *reserveInc;
-
2454
-
2455 // (The ~ operator converts the Proxy to a std::optional, which
-
2456 // simplifies later operations)
-
2457 if (auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops);
-
2458 baseFeeXRP && baseFeeXRP->native())
-
2459 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
-
2460
-
2461 if (auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
-
2462 reserveBaseXRP && reserveBaseXRP->native())
-
2463 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
-
2464
-
2465 if (auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
-
2466 reserveIncXRP && reserveIncXRP->native())
-
2467 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
-
2468
-
2469 // NOTE Use MultiApiJson to publish two slightly different JSON objects
-
2470 // for consumers supporting different API versions
-
2471 MultiApiJson multiObj{jvObj};
-
2472 multiObj.visit(
-
2473 RPC::apiVersion<1>, //
-
2474 [](Json::Value& jvTx) {
-
2475 // Type conversion for older API versions to string
-
2476 if (jvTx.isMember(jss::ledger_index))
-
2477 {
-
2478 jvTx[jss::ledger_index] =
-
2479 std::to_string(jvTx[jss::ledger_index].asUInt());
-
2480 }
-
2481 });
-
2482
-
2483 for (auto i = mStreamMaps[sValidations].begin();
-
2484 i != mStreamMaps[sValidations].end();)
-
2485 {
-
2486 if (auto p = i->second.lock())
-
2487 {
-
2488 multiObj.visit(
-
2489 p->getApiVersion(), //
-
2490 [&](Json::Value const& jv) { p->send(jv, true); });
-
2491 ++i;
-
2492 }
-
2493 else
-
2494 {
-
2495 i = mStreamMaps[sValidations].erase(i);
-
2496 }
-
2497 }
-
2498 }
-
2499}
-
2500
-
2501void
-
2502NetworkOPsImp::pubPeerStatus(std::function<Json::Value(void)> const& func)
-
2503{
-
2504 std::lock_guard sl(mSubLock);
-
2505
-
2506 if (!mStreamMaps[sPeerStatus].empty())
-
2507 {
-
2508 Json::Value jvObj(func());
-
2509
-
2510 jvObj[jss::type] = "peerStatusChange";
-
2511
-
2512 for (auto i = mStreamMaps[sPeerStatus].begin();
-
2513 i != mStreamMaps[sPeerStatus].end();)
-
2514 {
-
2515 InfoSub::pointer p = i->second.lock();
-
2516
-
2517 if (p)
-
2518 {
-
2519 p->send(jvObj, true);
-
2520 ++i;
-
2521 }
-
2522 else
-
2523 {
-
2524 i = mStreamMaps[sPeerStatus].erase(i);
-
2525 }
-
2526 }
-
2527 }
-
2528}
-
2529
-
2530void
-
2531NetworkOPsImp::setMode(OperatingMode om)
-
2532{
-
2533 using namespace std::chrono_literals;
-
2534 if (om == OperatingMode::CONNECTED)
-
2535 {
-
2536 if (app_.getLedgerMaster().getValidatedLedgerAge() < 1min)
-
2537 om = OperatingMode::SYNCING;
-
2538 }
-
2539 else if (om == OperatingMode::SYNCING)
-
2540 {
-
2541 if (app_.getLedgerMaster().getValidatedLedgerAge() >= 1min)
-
2542 om = OperatingMode::CONNECTED;
-
2543 }
-
2544
-
2545 if ((om > OperatingMode::CONNECTED) && isBlocked())
-
2546 om = OperatingMode::CONNECTED;
-
2547
-
2548 if (mMode == om)
-
2549 return;
-
2550
-
2551 mMode = om;
-
2552
-
2553 accounting_.mode(om);
-
2554
-
2555 JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
-
2556 pubServer();
-
2557}
-
2558
-
2559bool
-
2560NetworkOPsImp::recvValidation(
-
2561 std::shared_ptr<STValidation> const& val,
-
2562 std::string const& source)
-
2563{
-
2564 JLOG(m_journal.trace())
-
2565 << "recvValidation " << val->getLedgerHash() << " from " << source;
-
2566
-
2567 std::unique_lock lock(validationsMutex_);
-
2568 BypassAccept bypassAccept = BypassAccept::no;
-
2569 try
-
2570 {
-
2571 if (pendingValidations_.contains(val->getLedgerHash()))
-
2572 bypassAccept = BypassAccept::yes;
-
2573 else
-
2574 pendingValidations_.insert(val->getLedgerHash());
-
2575 scope_unlock unlock(lock);
-
2576 handleNewValidation(app_, val, source, bypassAccept, m_journal);
-
2577 }
-
2578 catch (std::exception const& e)
-
2579 {
-
2580 JLOG(m_journal.warn())
-
2581 << "Exception thrown for handling new validation "
-
2582 << val->getLedgerHash() << ": " << e.what();
-
2583 }
-
2584 catch (...)
-
2585 {
-
2586 JLOG(m_journal.warn())
-
2587 << "Unknown exception thrown for handling new validation "
-
2588 << val->getLedgerHash();
-
2589 }
-
2590 if (bypassAccept == BypassAccept::no)
-
2591 {
-
2592 pendingValidations_.erase(val->getLedgerHash());
-
2593 }
-
2594 lock.unlock();
-
2595
-
2596 pubValidation(val);
-
2597
-
2598 JLOG(m_journal.debug()) << [this, &val]() -> auto {
-
2599 std::stringstream ss;
-
2600 ss << "VALIDATION: " << val->render() << " master_key: ";
-
2601 auto master = app_.validators().getTrustedKey(val->getSignerPublic());
-
2602 if (master)
-
2603 {
-
2604 ss << toBase58(TokenType::NodePublic, *master);
-
2605 }
-
2606 else
-
2607 {
-
2608 ss << "none";
-
2609 }
-
2610 return ss.str();
-
2611 }();
-
2612
-
2613 // We will always relay trusted validations; if configured, we will
-
2614 // also relay all untrusted validations.
-
2615 return app_.config().RELAY_UNTRUSTED_VALIDATIONS == 1 || val->isTrusted();
-
2616}
-
2617
-
2618Json::Value
-
2619NetworkOPsImp::getConsensusInfo()
-
2620{
-
2621 return mConsensus.getJson(true);
-
2622}
-
2623
-
2624Json::Value
-
2625NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
-
2626{
-
2627 Json::Value info = Json::objectValue;
-
2628
-
2629 // System-level warnings
-
2630 {
-
2631 Json::Value warnings{Json::arrayValue};
-
2632 if (isAmendmentBlocked())
-
2633 {
-
2634 Json::Value& w = warnings.append(Json::objectValue);
-
2635 w[jss::id] = warnRPC_AMENDMENT_BLOCKED;
-
2636 w[jss::message] =
-
2637 "This server is amendment blocked, and must be updated to be "
-
2638 "able to stay in sync with the network.";
-
2639 }
-
2640 if (isUNLBlocked())
-
2641 {
-
2642 Json::Value& w = warnings.append(Json::objectValue);
-
2643 w[jss::id] = warnRPC_EXPIRED_VALIDATOR_LIST;
-
2644 w[jss::message] =
-
2645 "This server has an expired validator list. validators.txt "
-
2646 "may be incorrectly configured or some [validator_list_sites] "
-
2647 "may be unreachable.";
-
2648 }
-
2649 if (admin && isAmendmentWarned())
-
2650 {
-
2651 Json::Value& w = warnings.append(Json::objectValue);
-
2652 w[jss::id] = warnRPC_UNSUPPORTED_MAJORITY;
-
2653 w[jss::message] =
-
2654 "One or more unsupported amendments have reached majority. "
-
2655 "Upgrade to the latest version before they are activated "
-
2656 "to avoid being amendment blocked.";
-
2657 if (auto const expected =
-
2658 app_.getAmendmentTable().firstUnsupportedExpected())
-
2659 {
-
2660 auto& d = w[jss::details] = Json::objectValue;
-
2661 d[jss::expected_date] = expected->time_since_epoch().count();
-
2662 d[jss::expected_date_UTC] = to_string(*expected);
-
2663 }
-
2664 }
-
2665
-
2666 if (warnings.size())
-
2667 info[jss::warnings] = std::move(warnings);
-
2668 }
-
2669
-
2670 // hostid: unique string describing the machine
-
2671 if (human)
-
2672 info[jss::hostid] = getHostId(admin);
-
2673
-
2674 // domain: if configured with a domain, report it:
-
2675 if (!app_.config().SERVER_DOMAIN.empty())
-
2676 info[jss::server_domain] = app_.config().SERVER_DOMAIN;
-
2677
-
2678 info[jss::build_version] = BuildInfo::getVersionString();
-
2679
-
2680 info[jss::server_state] = strOperatingMode(admin);
-
2681
-
2682 info[jss::time] = to_string(std::chrono::floor<std::chrono::microseconds>(
-
2683 std::chrono::system_clock::now()));
-
2684
-
2685 if (needNetworkLedger_)
-
2686 info[jss::network_ledger] = "waiting";
-
2687
-
2688 info[jss::validation_quorum] =
-
2689 static_cast<Json::UInt>(app_.validators().quorum());
-
2690
-
2691 if (admin)
-
2692 {
-
2693 switch (app_.config().NODE_SIZE)
-
2694 {
-
2695 case 0:
-
2696 info[jss::node_size] = "tiny";
-
2697 break;
-
2698 case 1:
-
2699 info[jss::node_size] = "small";
-
2700 break;
-
2701 case 2:
-
2702 info[jss::node_size] = "medium";
-
2703 break;
-
2704 case 3:
-
2705 info[jss::node_size] = "large";
-
2706 break;
-
2707 case 4:
-
2708 info[jss::node_size] = "huge";
-
2709 break;
-
2710 }
-
2711
-
2712 auto when = app_.validators().expires();
-
2713
-
2714 if (!human)
-
2715 {
-
2716 if (when)
-
2717 info[jss::validator_list_expires] =
-
2718 safe_cast<Json::UInt>(when->time_since_epoch().count());
-
2719 else
-
2720 info[jss::validator_list_expires] = 0;
-
2721 }
-
2722 else
-
2723 {
-
2724 auto& x = (info[jss::validator_list] = Json::objectValue);
-
2725
-
2726 x[jss::count] = static_cast<Json::UInt>(app_.validators().count());
-
2727
-
2728 if (when)
-
2729 {
-
2730 if (*when == TimeKeeper::time_point::max())
-
2731 {
-
2732 x[jss::expiration] = "never";
-
2733 x[jss::status] = "active";
-
2734 }
-
2735 else
-
2736 {
-
2737 x[jss::expiration] = to_string(*when);
-
2738
-
2739 if (*when > app_.timeKeeper().now())
-
2740 x[jss::status] = "active";
-
2741 else
-
2742 x[jss::status] = "expired";
-
2743 }
-
2744 }
-
2745 else
-
2746 {
-
2747 x[jss::status] = "unknown";
-
2748 x[jss::expiration] = "unknown";
-
2749 }
-
2750 }
-
2751
-
2752#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH)
-
2753 {
-
2754 auto& x = (info[jss::git] = Json::objectValue);
-
2755#ifdef GIT_COMMIT_HASH
-
2756 x[jss::hash] = GIT_COMMIT_HASH;
-
2757#endif
-
2758#ifdef GIT_BRANCH
-
2759 x[jss::branch] = GIT_BRANCH;
-
2760#endif
-
2761 }
-
2762#endif
-
2763 }
-
2764 info[jss::io_latency_ms] =
-
2765 static_cast<Json::UInt>(app_.getIOLatency().count());
-
2766
-
2767 if (admin)
-
2768 {
-
2769 if (auto const localPubKey = app_.validators().localPublicKey();
-
2770 localPubKey && app_.getValidationPublicKey())
-
2771 {
-
2772 info[jss::pubkey_validator] =
-
2773 toBase58(TokenType::NodePublic, localPubKey.value());
-
2774 }
-
2775 else
-
2776 {
-
2777 info[jss::pubkey_validator] = "none";
-
2778 }
-
2779 }
-
2780
-
2781 if (counters)
-
2782 {
-
2783 info[jss::counters] = app_.getPerfLog().countersJson();
-
2784
-
2785 Json::Value nodestore(Json::objectValue);
-
2786 app_.getNodeStore().getCountsJson(nodestore);
-
2787 info[jss::counters][jss::nodestore] = nodestore;
-
2788 info[jss::current_activities] = app_.getPerfLog().currentJson();
-
2789 }
-
2790
-
2791 info[jss::pubkey_node] =
-
2792 toBase58(TokenType::NodePublic, app_.nodeIdentity().first);
-
2793
-
2794 info[jss::complete_ledgers] = app_.getLedgerMaster().getCompleteLedgers();
-
2795
-
2796 if (amendmentBlocked_)
-
2797 info[jss::amendment_blocked] = true;
-
2798
-
2799 auto const fp = m_ledgerMaster.getFetchPackCacheSize();
-
2800
-
2801 if (fp != 0)
-
2802 info[jss::fetch_pack] = Json::UInt(fp);
-
2803
-
2804 info[jss::peers] = Json::UInt(app_.overlay().size());
-
2805
-
2806 Json::Value lastClose = Json::objectValue;
-
2807 lastClose[jss::proposers] = Json::UInt(mConsensus.prevProposers());
-
2808
-
2809 if (human)
-
2810 {
-
2811 lastClose[jss::converge_time_s] =
-
2812 std::chrono::duration<double>{mConsensus.prevRoundTime()}.count();
-
2813 }
-
2814 else
-
2815 {
-
2816 lastClose[jss::converge_time] =
-
2817 Json::Int(mConsensus.prevRoundTime().count());
-
2818 }
-
2819
-
2820 info[jss::last_close] = lastClose;
-
2821
-
2822 // info[jss::consensus] = mConsensus.getJson();
-
2823
-
2824 if (admin)
-
2825 info[jss::load] = m_job_queue.getJson();
-
2826
-
2827 if (auto const netid = app_.overlay().networkID())
-
2828 info[jss::network_id] = static_cast<Json::UInt>(*netid);
-
2829
-
2830 auto const escalationMetrics =
-
2831 app_.getTxQ().getMetrics(*app_.openLedger().current());
-
2832
-
2833 auto const loadFactorServer = app_.getFeeTrack().getLoadFactor();
-
2834 auto const loadBaseServer = app_.getFeeTrack().getLoadBase();
-
2835 /* Scale the escalated fee level to unitless "load factor".
-
2836 In practice, this just strips the units, but it will continue
-
2837 to work correctly if either base value ever changes. */
-
2838 auto const loadFactorFeeEscalation =
-
2839 mulDiv(
-
2840 escalationMetrics.openLedgerFeeLevel,
-
2841 loadBaseServer,
-
2842 escalationMetrics.referenceFeeLevel)
-
2843 .value_or(ripple::muldiv_max);
-
2844
-
2845 auto const loadFactor = std::max(
-
2846 safe_cast<std::uint64_t>(loadFactorServer), loadFactorFeeEscalation);
-
2847
-
2848 if (!human)
-
2849 {
-
2850 info[jss::load_base] = loadBaseServer;
-
2851 info[jss::load_factor] = trunc32(loadFactor);
-
2852 info[jss::load_factor_server] = loadFactorServer;
-
2853
-
2854 /* Json::Value doesn't support uint64, so clamp to max
-
2855 uint32 value. This is mostly theoretical, since there
-
2856 probably isn't enough extant XRP to drive the factor
-
2857 that high.
-
2858 */
-
2859 info[jss::load_factor_fee_escalation] =
-
2860 escalationMetrics.openLedgerFeeLevel.jsonClipped();
-
2861 info[jss::load_factor_fee_queue] =
-
2862 escalationMetrics.minProcessingFeeLevel.jsonClipped();
-
2863 info[jss::load_factor_fee_reference] =
-
2864 escalationMetrics.referenceFeeLevel.jsonClipped();
-
2865 }
-
2866 else
-
2867 {
-
2868 info[jss::load_factor] =
-
2869 static_cast<double>(loadFactor) / loadBaseServer;
-
2870
-
2871 if (loadFactorServer != loadFactor)
-
2872 info[jss::load_factor_server] =
-
2873 static_cast<double>(loadFactorServer) / loadBaseServer;
-
2874
-
2875 if (admin)
-
2876 {
-
2877 std::uint32_t fee = app_.getFeeTrack().getLocalFee();
-
2878 if (fee != loadBaseServer)
-
2879 info[jss::load_factor_local] =
-
2880 static_cast<double>(fee) / loadBaseServer;
-
2881 fee = app_.getFeeTrack().getRemoteFee();
-
2882 if (fee != loadBaseServer)
-
2883 info[jss::load_factor_net] =
-
2884 static_cast<double>(fee) / loadBaseServer;
-
2885 fee = app_.getFeeTrack().getClusterFee();
-
2886 if (fee != loadBaseServer)
-
2887 info[jss::load_factor_cluster] =
-
2888 static_cast<double>(fee) / loadBaseServer;
-
2889 }
-
2890 if (escalationMetrics.openLedgerFeeLevel !=
-
2891 escalationMetrics.referenceFeeLevel &&
-
2892 (admin || loadFactorFeeEscalation != loadFactor))
-
2893 info[jss::load_factor_fee_escalation] =
-
2894 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
-
2895 escalationMetrics.referenceFeeLevel);
-
2896 if (escalationMetrics.minProcessingFeeLevel !=
-
2897 escalationMetrics.referenceFeeLevel)
-
2898 info[jss::load_factor_fee_queue] =
-
2899 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
-
2900 escalationMetrics.referenceFeeLevel);
-
2901 }
-
2902
-
2903 bool valid = false;
-
2904 auto lpClosed = m_ledgerMaster.getValidatedLedger();
-
2905
-
2906 if (lpClosed)
-
2907 valid = true;
-
2908 else
-
2909 lpClosed = m_ledgerMaster.getClosedLedger();
-
2910
-
2911 if (lpClosed)
-
2912 {
-
2913 XRPAmount const baseFee = lpClosed->fees().base;
-
2914 Json::Value l(Json::objectValue);
-
2915 l[jss::seq] = Json::UInt(lpClosed->info().seq);
-
2916 l[jss::hash] = to_string(lpClosed->info().hash);
-
2917
-
2918 if (!human)
-
2919 {
-
2920 l[jss::base_fee] = baseFee.jsonClipped();
-
2921 l[jss::reserve_base] =
-
2922 lpClosed->fees().accountReserve(0).jsonClipped();
-
2923 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
-
2924 l[jss::close_time] = Json::Value::UInt(
-
2925 lpClosed->info().closeTime.time_since_epoch().count());
-
2926 }
-
2927 else
-
2928 {
-
2929 l[jss::base_fee_xrp] = baseFee.decimalXRP();
-
2930 l[jss::reserve_base_xrp] =
-
2931 lpClosed->fees().accountReserve(0).decimalXRP();
-
2932 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
-
2933
-
2934 if (auto const closeOffset = app_.timeKeeper().closeOffset();
-
2935 std::abs(closeOffset.count()) >= 60)
-
2936 l[jss::close_time_offset] =
-
2937 static_cast<std::uint32_t>(closeOffset.count());
-
2938
-
2939 constexpr std::chrono::seconds highAgeThreshold{1000000};
-
2940 if (m_ledgerMaster.haveValidated())
-
2941 {
-
2942 auto const age = m_ledgerMaster.getValidatedLedgerAge();
-
2943 l[jss::age] =
-
2944 Json::UInt(age < highAgeThreshold ? age.count() : 0);
-
2945 }
-
2946 else
-
2947 {
-
2948 auto lCloseTime = lpClosed->info().closeTime;
-
2949 auto closeTime = app_.timeKeeper().closeTime();
-
2950 if (lCloseTime <= closeTime)
-
2951 {
-
2952 using namespace std::chrono_literals;
-
2953 auto age = closeTime - lCloseTime;
-
2954 l[jss::age] =
-
2955 Json::UInt(age < highAgeThreshold ? age.count() : 0);
-
2956 }
-
2957 }
-
2958 }
-
2959
-
2960 if (valid)
-
2961 info[jss::validated_ledger] = l;
-
2962 else
-
2963 info[jss::closed_ledger] = l;
-
2964
-
2965 auto lpPublished = m_ledgerMaster.getPublishedLedger();
-
2966 if (!lpPublished)
-
2967 info[jss::published_ledger] = "none";
-
2968 else if (lpPublished->info().seq != lpClosed->info().seq)
-
2969 info[jss::published_ledger] = lpPublished->info().seq;
-
2970 }
-
2971
-
2972 accounting_.json(info);
-
2973 info[jss::uptime] = UptimeClock::now().time_since_epoch().count();
-
2974 info[jss::jq_trans_overflow] =
-
2975 std::to_string(app_.overlay().getJqTransOverflow());
-
2976 info[jss::peer_disconnects] =
-
2977 std::to_string(app_.overlay().getPeerDisconnect());
-
2978 info[jss::peer_disconnects_resources] =
-
2979 std::to_string(app_.overlay().getPeerDisconnectCharges());
-
2980
-
2981 // This array must be sorted in increasing order.
-
2982 static constexpr std::array<std::string_view, 7> protocols{
-
2983 "http", "https", "peer", "ws", "ws2", "wss", "wss2"};
-
2984 static_assert(std::is_sorted(std::begin(protocols), std::end(protocols)));
-
2985 {
-
2986 Json::Value ports{Json::arrayValue};
-
2987 for (auto const& port : app_.getServerHandler().setup().ports)
-
2988 {
-
2989 // Don't publish admin ports for non-admin users
-
2990 if (!admin &&
-
2991 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
-
2992 port.admin_user.empty() && port.admin_password.empty()))
-
2993 continue;
-
2994 std::vector<std::string> proto;
-
2995 std::set_intersection(
-
2996 std::begin(port.protocol),
-
2997 std::end(port.protocol),
-
2998 std::begin(protocols),
-
2999 std::end(protocols),
-
3000 std::back_inserter(proto));
-
3001 if (!proto.empty())
-
3002 {
-
3003 auto& jv = ports.append(Json::Value(Json::objectValue));
-
3004 jv[jss::port] = std::to_string(port.port);
-
3005 jv[jss::protocol] = Json::Value{Json::arrayValue};
-
3006 for (auto const& p : proto)
-
3007 jv[jss::protocol].append(p);
-
3008 }
-
3009 }
-
3010
-
3011 if (app_.config().exists(SECTION_PORT_GRPC))
-
3012 {
-
3013 auto const& grpcSection = app_.config().section(SECTION_PORT_GRPC);
-
3014 auto const optPort = grpcSection.get("port");
-
3015 if (optPort && grpcSection.get("ip"))
-
3016 {
-
3017 auto& jv = ports.append(Json::Value(Json::objectValue));
-
3018 jv[jss::port] = *optPort;
-
3019 jv[jss::protocol] = Json::Value{Json::arrayValue};
-
3020 jv[jss::protocol].append("grpc");
-
3021 }
-
3022 }
-
3023 info[jss::ports] = std::move(ports);
-
3024 }
-
3025
-
3026 return info;
-
3027}
-
3028
-
3029void
-
3030NetworkOPsImp::clearLedgerFetch()
-
3031{
-
3032 app_.getInboundLedgers().clearFailures();
-
3033}
-
3034
-
3035Json::Value
-
3036NetworkOPsImp::getLedgerFetchInfo()
-
3037{
-
3038 return app_.getInboundLedgers().getInfo();
-
3039}
-
3040
-
3041void
-
3042NetworkOPsImp::pubProposedTransaction(
-
3043 std::shared_ptr<ReadView const> const& ledger,
-
3044 std::shared_ptr<STTx const> const& transaction,
-
3045 TER result)
-
3046{
-
3047 // never publish an inner txn inside a batch txn
-
3048 if (transaction->isFlag(tfInnerBatchTxn) &&
-
3049 ledger->rules().enabled(featureBatch))
-
3050 return;
-
3051
-
3052 MultiApiJson jvObj =
-
3053 transJson(transaction, result, false, ledger, std::nullopt);
-
3054
-
3055 {
-
3056 std::lock_guard sl(mSubLock);
-
3057
-
3058 auto it = mStreamMaps[sRTTransactions].begin();
-
3059 while (it != mStreamMaps[sRTTransactions].end())
-
3060 {
-
3061 InfoSub::pointer p = it->second.lock();
-
3062
-
3063 if (p)
-
3064 {
-
3065 jvObj.visit(
-
3066 p->getApiVersion(), //
-
3067 [&](Json::Value const& jv) { p->send(jv, true); });
-
3068 ++it;
-
3069 }
-
3070 else
-
3071 {
-
3072 it = mStreamMaps[sRTTransactions].erase(it);
-
3073 }
-
3074 }
-
3075 }
-
3076
-
3077 pubProposedAccountTransaction(ledger, transaction, result);
-
3078}
-
3079
-
3080void
-
3081NetworkOPsImp::pubLedger(std::shared_ptr<ReadView const> const& lpAccepted)
-
3082{
-
3083 // Ledgers are published only when they acquire sufficient validations
-
3084 // Holes are filled across connection loss or other catastrophe
-
3085
-
3086 std::shared_ptr<AcceptedLedger> alpAccepted =
-
3087 app_.getAcceptedLedgerCache().fetch(lpAccepted->info().hash);
-
3088 if (!alpAccepted)
-
3089 {
-
3090 alpAccepted = std::make_shared<AcceptedLedger>(lpAccepted, app_);
-
3091 app_.getAcceptedLedgerCache().canonicalize_replace_client(
-
3092 lpAccepted->info().hash, alpAccepted);
-
3093 }
-
3094
-
3095 XRPL_ASSERT(
-
3096 alpAccepted->getLedger().get() == lpAccepted.get(),
-
3097 "ripple::NetworkOPsImp::pubLedger : accepted input");
-
3098
-
3099 {
-
3100 JLOG(m_journal.debug())
-
3101 << "Publishing ledger " << lpAccepted->info().seq << " "
-
3102 << lpAccepted->info().hash;
-
3103
-
3104 std::lock_guard sl(mSubLock);
-
3105
-
3106 if (!mStreamMaps[sLedger].empty())
-
3107 {
-
3108 Json::Value jvObj(Json::objectValue);
-
3109
-
3110 jvObj[jss::type] = "ledgerClosed";
-
3111 jvObj[jss::ledger_index] = lpAccepted->info().seq;
-
3112 jvObj[jss::ledger_hash] = to_string(lpAccepted->info().hash);
-
3113 jvObj[jss::ledger_time] = Json::Value::UInt(
-
3114 lpAccepted->info().closeTime.time_since_epoch().count());
-
3115
-
3116 if (!lpAccepted->rules().enabled(featureXRPFees))
-
3117 jvObj[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED;
-
3118 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
-
3119 jvObj[jss::reserve_base] =
-
3120 lpAccepted->fees().accountReserve(0).jsonClipped();
-
3121 jvObj[jss::reserve_inc] =
-
3122 lpAccepted->fees().increment.jsonClipped();
-
3123
-
3124 jvObj[jss::txn_count] = Json::UInt(alpAccepted->size());
-
3125
-
3126 if (mMode >= OperatingMode::SYNCING)
-
3127 {
-
3128 jvObj[jss::validated_ledgers] =
-
3129 app_.getLedgerMaster().getCompleteLedgers();
-
3130 }
-
3131
-
3132 auto it = mStreamMaps[sLedger].begin();
-
3133 while (it != mStreamMaps[sLedger].end())
-
3134 {
-
3135 InfoSub::pointer p = it->second.lock();
-
3136 if (p)
-
3137 {
-
3138 p->send(jvObj, true);
-
3139 ++it;
-
3140 }
-
3141 else
-
3142 it = mStreamMaps[sLedger].erase(it);
-
3143 }
-
3144 }
-
3145
-
3146 if (!mStreamMaps[sBookChanges].empty())
-
3147 {
-
3148 Json::Value jvObj = ripple::RPC::computeBookChanges(lpAccepted);
-
3149
-
3150 auto it = mStreamMaps[sBookChanges].begin();
-
3151 while (it != mStreamMaps[sBookChanges].end())
-
3152 {
-
3153 InfoSub::pointer p = it->second.lock();
-
3154 if (p)
-
3155 {
-
3156 p->send(jvObj, true);
-
3157 ++it;
-
3158 }
-
3159 else
-
3160 it = mStreamMaps[sBookChanges].erase(it);
-
3161 }
-
3162 }
-
3163
-
3164 {
-
3165 static bool firstTime = true;
-
3166 if (firstTime)
-
3167 {
-
3168 // First validated ledger, start delayed SubAccountHistory
-
3169 firstTime = false;
-
3170 for (auto& outer : mSubAccountHistory)
-
3171 {
-
3172 for (auto& inner : outer.second)
-
3173 {
-
3174 auto& subInfo = inner.second;
-
3175 if (subInfo.index_->separationLedgerSeq_ == 0)
-
3176 {
-
3177 subAccountHistoryStart(
-
3178 alpAccepted->getLedger(), subInfo);
-
3179 }
-
3180 }
-
3181 }
-
3182 }
-
3183 }
-
3184 }
-
3185
-
3186 // Don't lock since pubAcceptedTransaction is locking.
-
3187 for (auto const& accTx : *alpAccepted)
-
3188 {
-
3189 JLOG(m_journal.trace()) << "pubAccepted: " << accTx->getJson();
-
3190 pubValidatedTransaction(
-
3191 lpAccepted, *accTx, accTx == *(--alpAccepted->end()));
-
3192 }
-
3193}
-
3194
-
3195void
-
3196NetworkOPsImp::reportFeeChange()
-
3197{
-
3198 ServerFeeSummary f{
-
3199 app_.openLedger().current()->fees().base,
-
3200 app_.getTxQ().getMetrics(*app_.openLedger().current()),
-
3201 app_.getFeeTrack()};
-
3202
-
3203 // only schedule the job if something has changed
-
3204 if (f != mLastFeeSummary)
-
3205 {
-
3206 m_job_queue.addJob(
-
3207 jtCLIENT_FEE_CHANGE, "reportFeeChange->pubServer", [this]() {
-
3208 pubServer();
-
3209 });
-
3210 }
-
3211}
-
3212
-
3213void
-
3214NetworkOPsImp::reportConsensusStateChange(ConsensusPhase phase)
-
3215{
-
3216 m_job_queue.addJob(
-
3217 jtCLIENT_CONSENSUS,
-
3218 "reportConsensusStateChange->pubConsensus",
-
3219 [this, phase]() { pubConsensus(phase); });
-
3220}
-
3221
-
3222inline void
-
3223NetworkOPsImp::updateLocalTx(ReadView const& view)
-
3224{
-
3225 m_localTX->sweep(view);
-
3226}
-
3227inline std::size_t
-
3228NetworkOPsImp::getLocalTxCount()
-
3229{
-
3230 return m_localTX->size();
-
3231}
-
3232
-
3233// This routine should only be used to publish accepted or validated
-
3234// transactions.
-
3235MultiApiJson
-
3236NetworkOPsImp::transJson(
-
3237 std::shared_ptr<STTx const> const& transaction,
-
3238 TER result,
-
3239 bool validated,
-
3240 std::shared_ptr<ReadView const> const& ledger,
-
3241 std::optional<std::reference_wrapper<TxMeta const>> meta)
-
3242{
-
3243 Json::Value jvObj(Json::objectValue);
-
3244 std::string sToken;
-
3245 std::string sHuman;
-
3246
-
3247 transResultInfo(result, sToken, sHuman);
-
3248
-
3249 jvObj[jss::type] = "transaction";
-
3250 // NOTE jvObj is not a finished object for either API version. After
-
3251 // it's populated, we need to finish it for a specific API version. This is
-
3252 // done in a loop, near the end of this function.
-
3253 jvObj[jss::transaction] =
-
3254 transaction->getJson(JsonOptions::disable_API_prior_V2, false);
-
3255
-
3256 if (meta)
-
3257 {
-
3258 jvObj[jss::meta] = meta->get().getJson(JsonOptions::none);
-
3259 RPC::insertDeliveredAmount(
-
3260 jvObj[jss::meta], *ledger, transaction, meta->get());
-
3261 RPC::insertMPTokenIssuanceID(
-
3262 jvObj[jss::meta], transaction, meta->get());
-
3263 }
-
3264
-
3265 // add CTID where the needed data for it exists
-
3266 if (auto const& lookup = ledger->txRead(transaction->getTransactionID());
-
3267 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
-
3268 {
-
3269 uint32_t const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
-
3270 uint32_t netID = app_.config().NETWORK_ID;
-
3271 if (transaction->isFieldPresent(sfNetworkID))
-
3272 netID = transaction->getFieldU32(sfNetworkID);
-
3273
-
3274 if (std::optional<std::string> ctid =
-
3275 RPC::encodeCTID(ledger->info().seq, txnSeq, netID);
-
3276 ctid)
-
3277 jvObj[jss::ctid] = *ctid;
-
3278 }
-
3279 if (!ledger->open())
-
3280 jvObj[jss::ledger_hash] = to_string(ledger->info().hash);
-
3281
-
3282 if (validated)
-
3283 {
-
3284 jvObj[jss::ledger_index] = ledger->info().seq;
-
3285 jvObj[jss::transaction][jss::date] =
-
3286 ledger->info().closeTime.time_since_epoch().count();
-
3287 jvObj[jss::validated] = true;
-
3288 jvObj[jss::close_time_iso] = to_string_iso(ledger->info().closeTime);
-
3289
-
3290 // WRITEME: Put the account next seq here
-
3291 }
-
3292 else
-
3293 {
-
3294 jvObj[jss::validated] = false;
-
3295 jvObj[jss::ledger_current_index] = ledger->info().seq;
-
3296 }
-
3297
-
3298 jvObj[jss::status] = validated ? "closed" : "proposed";
-
3299 jvObj[jss::engine_result] = sToken;
-
3300 jvObj[jss::engine_result_code] = result;
-
3301 jvObj[jss::engine_result_message] = sHuman;
-
3302
-
3303 if (transaction->getTxnType() == ttOFFER_CREATE)
-
3304 {
-
3305 auto const account = transaction->getAccountID(sfAccount);
-
3306 auto const amount = transaction->getFieldAmount(sfTakerGets);
-
3307
-
3308 // If the offer create is not self funded then add the owner balance
-
3309 if (account != amount.issue().account)
-
3310 {
-
3311 auto const ownerFunds = accountFunds(
-
3312 *ledger,
-
3313 account,
-
3314 amount,
-
3315 fhIGNORE_FREEZE,
-
3316 app_.journal("View"));
-
3317 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
-
3318 }
-
3319 }
-
3320
-
3321 std::string const hash = to_string(transaction->getTransactionID());
-
3322 MultiApiJson multiObj{jvObj};
-
3323 forAllApiVersions(
-
3324 multiObj.visit(), //
-
3325 [&]<unsigned Version>(
-
3326 Json::Value& jvTx, std::integral_constant<unsigned, Version>) {
-
3327 RPC::insertDeliverMax(
-
3328 jvTx[jss::transaction], transaction->getTxnType(), Version);
-
3329
-
3330 if constexpr (Version > 1)
-
3331 {
-
3332 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
-
3333 jvTx[jss::hash] = hash;
-
3334 }
-
3335 else
-
3336 {
-
3337 jvTx[jss::transaction][jss::hash] = hash;
-
3338 }
-
3339 });
-
3340
-
3341 return multiObj;
-
3342}
-
3343
-
3344void
-
3345NetworkOPsImp::pubValidatedTransaction(
-
3346 std::shared_ptr<ReadView const> const& ledger,
-
3347 AcceptedLedgerTx const& transaction,
-
3348 bool last)
-
3349{
-
3350 auto const& stTxn = transaction.getTxn();
-
3351
-
3352 // Create two different Json objects, for different API versions
-
3353 auto const metaRef = std::ref(transaction.getMeta());
-
3354 auto const trResult = transaction.getResult();
-
3355 MultiApiJson jvObj = transJson(stTxn, trResult, true, ledger, metaRef);
-
3356
-
3357 {
-
3358 std::lock_guard sl(mSubLock);
-
3359
-
3360 auto it = mStreamMaps[sTransactions].begin();
-
3361 while (it != mStreamMaps[sTransactions].end())
-
3362 {
-
3363 InfoSub::pointer p = it->second.lock();
-
3364
-
3365 if (p)
-
3366 {
-
3367 jvObj.visit(
-
3368 p->getApiVersion(), //
-
3369 [&](Json::Value const& jv) { p->send(jv, true); });
-
3370 ++it;
-
3371 }
-
3372 else
-
3373 it = mStreamMaps[sTransactions].erase(it);
-
3374 }
-
3375
-
3376 it = mStreamMaps[sRTTransactions].begin();
+
66#include <xrpl/protocol/NFTSyntheticSerializer.h>
+
67#include <xrpl/protocol/RPCErr.h>
+
68#include <xrpl/protocol/TxFlags.h>
+
69#include <xrpl/protocol/jss.h>
+
70#include <xrpl/resource/Fees.h>
+
71#include <xrpl/resource/ResourceManager.h>
+
72
+
73#include <boost/asio/ip/host_name.hpp>
+
74#include <boost/asio/steady_timer.hpp>
+
75
+
76#include <algorithm>
+
77#include <exception>
+
78#include <mutex>
+
79#include <optional>
+
80#include <set>
+
81#include <sstream>
+
82#include <string>
+
83#include <tuple>
+
84#include <unordered_map>
+
85
+
86namespace ripple {
+
87
+
88class NetworkOPsImp final : public NetworkOPs
+
89{
+
94 class TransactionStatus
+
95 {
+
96 public:
+
97 std::shared_ptr<Transaction> const transaction;
+
98 bool const admin;
+
99 bool const local;
+
100 FailHard const failType;
+
101 bool applied = false;
+
102 TER result;
+
103
+
104 TransactionStatus(
+
105 std::shared_ptr<Transaction> t,
+
106 bool a,
+
107 bool l,
+
108 FailHard f)
+
109 : transaction(t), admin(a), local(l), failType(f)
+
110 {
+
111 XRPL_ASSERT(
+
112 local || failType == FailHard::no,
+
113 "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : "
+
114 "valid inputs");
+
115 }
+
116 };
+
117
+
121 enum class DispatchState : unsigned char {
+
122 none,
+
123 scheduled,
+
124 running,
+
125 };
+
126
+
127 static std::array<char const*, 5> const states_;
+
128
+
143 class StateAccounting
+
144 {
+
145 struct Counters
+
146 {
+
147 explicit Counters() = default;
+
148
+
149 std::uint64_t transitions = 0;
+
150 std::chrono::microseconds dur = std::chrono::microseconds(0);
+
151 };
+
152
+
153 OperatingMode mode_ = OperatingMode::DISCONNECTED;
+
154 std::array<Counters, 5> counters_;
+
155 mutable std::mutex mutex_;
+
156 std::chrono::steady_clock::time_point start_ =
+
157 std::chrono::steady_clock::now();
+
158 std::chrono::steady_clock::time_point const processStart_ = start_;
+
159 std::uint64_t initialSyncUs_{0};
+
160 static std::array<Json::StaticString const, 5> const states_;
+
161
+
162 public:
+
163 explicit StateAccounting()
+
164 {
+
165 counters_[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
+
166 .transitions = 1;
+
167 }
+
168
+
175 void
+
176 mode(OperatingMode om);
+
177
+
183 void
+
184 json(Json::Value& obj) const;
+
185
+
186 struct CounterData
+
187 {
+
188 decltype(counters_) counters;
+
189 decltype(mode_) mode;
+
190 decltype(start_) start;
+
191 decltype(initialSyncUs_) initialSyncUs;
+
192 };
+
193
+
194 CounterData
+
195 getCounterData() const
+
196 {
+
197 std::lock_guard lock(mutex_);
+
198 return {counters_, mode_, start_, initialSyncUs_};
+
199 }
+
200 };
+
201
+
203 struct ServerFeeSummary
+
204 {
+
205 ServerFeeSummary() = default;
+
206
+
207 ServerFeeSummary(
+
208 XRPAmount fee,
+
209 TxQ::Metrics&& escalationMetrics,
+
210 LoadFeeTrack const& loadFeeTrack);
+
211 bool
+
212 operator!=(ServerFeeSummary const& b) const;
+
213
+
214 bool
+
215 operator==(ServerFeeSummary const& b) const
+
216 {
+
217 return !(*this != b);
+
218 }
+
219
+
220 std::uint32_t loadFactorServer = 256;
+
221 std::uint32_t loadBaseServer = 256;
+
222 XRPAmount baseFee{10};
+
223 std::optional<TxQ::Metrics> em = std::nullopt;
+
224 };
+
225
+
226public:
+
227 NetworkOPsImp(
+
228 Application& app,
+
229 NetworkOPs::clock_type& clock,
+
230 bool standalone,
+
231 std::size_t minPeerCount,
+
232 bool start_valid,
+
233 JobQueue& job_queue,
+
234 LedgerMaster& ledgerMaster,
+
235 ValidatorKeys const& validatorKeys,
+
236 boost::asio::io_service& io_svc,
+
237 beast::Journal journal,
+
238 beast::insight::Collector::ptr const& collector)
+
239 : app_(app)
+
240 , m_journal(journal)
+
241 , m_localTX(make_LocalTxs())
+
242 , mMode(start_valid ? OperatingMode::FULL : OperatingMode::DISCONNECTED)
+
243 , heartbeatTimer_(io_svc)
+
244 , clusterTimer_(io_svc)
+
245 , accountHistoryTxTimer_(io_svc)
+
246 , mConsensus(
+
247 app,
+
248 make_FeeVote(
+
249 setup_FeeVote(app_.config().section("voting")),
+
250 app_.logs().journal("FeeVote")),
+
251 ledgerMaster,
+
252 *m_localTX,
+
253 app.getInboundTransactions(),
+
254 beast::get_abstract_clock<std::chrono::steady_clock>(),
+
255 validatorKeys,
+
256 app_.logs().journal("LedgerConsensus"))
+
257 , validatorPK_(
+
258 validatorKeys.keys ? validatorKeys.keys->publicKey
+
259 : decltype(validatorPK_){})
+
260 , validatorMasterPK_(
+
261 validatorKeys.keys ? validatorKeys.keys->masterPublicKey
+
262 : decltype(validatorMasterPK_){})
+
263 , m_ledgerMaster(ledgerMaster)
+
264 , m_job_queue(job_queue)
+
265 , m_standalone(standalone)
+
266 , minPeerCount_(start_valid ? 0 : minPeerCount)
+
267 , m_stats(std::bind(&NetworkOPsImp::collect_metrics, this), collector)
+
268 {
+
269 }
+
270
+
271 ~NetworkOPsImp() override
+
272 {
+
273 // This clear() is necessary to ensure the shared_ptrs in this map get
+
274 // destroyed NOW because the objects in this map invoke methods on this
+
275 // class when they are destroyed
+
276 mRpcSubMap.clear();
+
277 }
+
278
+
279public:
+
280 OperatingMode
+
281 getOperatingMode() const override;
+
282
+
283 std::string
+
284 strOperatingMode(OperatingMode const mode, bool const admin) const override;
+
285
+
286 std::string
+
287 strOperatingMode(bool const admin = false) const override;
+
288
+
289 //
+
290 // Transaction operations.
+
291 //
+
292
+
293 // Must complete immediately.
+
294 void
+
295 submitTransaction(std::shared_ptr<STTx const> const&) override;
+
296
+
297 void
+
298 processTransaction(
+
299 std::shared_ptr<Transaction>& transaction,
+
300 bool bUnlimited,
+
301 bool bLocal,
+
302 FailHard failType) override;
+
303
+
304 void
+
305 processTransactionSet(CanonicalTXSet const& set) override;
+
306
+
315 void
+
316 doTransactionSync(
+
317 std::shared_ptr<Transaction> transaction,
+
318 bool bUnlimited,
+
319 FailHard failType);
+
320
+
330 void
+
331 doTransactionAsync(
+
332 std::shared_ptr<Transaction> transaction,
+
333 bool bUnlimited,
+
334 FailHard failtype);
+
335
+
336private:
+
337 bool
+
338 preProcessTransaction(std::shared_ptr<Transaction>& transaction);
+
339
+
340 void
+
341 doTransactionSyncBatch(
+
342 std::unique_lock<std::mutex>& lock,
+
343 std::function<bool(std::unique_lock<std::mutex> const&)> retryCallback);
+
344
+
345public:
+
349 void
+
350 transactionBatch();
+
351
+
357 void
+
358 apply(std::unique_lock<std::mutex>& batchLock);
+
359
+
360 //
+
361 // Owner functions.
+
362 //
+
363
+
364 Json::Value
+
365 getOwnerInfo(
+
366 std::shared_ptr<ReadView const> lpLedger,
+
367 AccountID const& account) override;
+
368
+
369 //
+
370 // Book functions.
+
371 //
+
372
+
373 void
+
374 getBookPage(
+
375 std::shared_ptr<ReadView const>& lpLedger,
+
376 Book const&,
+
377 AccountID const& uTakerID,
+
378 bool const bProof,
+
379 unsigned int iLimit,
+
380 Json::Value const& jvMarker,
+
381 Json::Value& jvResult) override;
+
382
+
383 // Ledger proposal/close functions.
+
384 bool
+
385 processTrustedProposal(RCLCxPeerPos proposal) override;
+
386
+
387 bool
+
388 recvValidation(
+
389 std::shared_ptr<STValidation> const& val,
+
390 std::string const& source) override;
+
391
+
392 void
+
393 mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire) override;
+
394
+
395 // Network state machine.
+
396
+
397 // Used for the "jump" case.
+
398private:
+
399 void
+
400 switchLastClosedLedger(std::shared_ptr<Ledger const> const& newLCL);
+
401 bool
+
402 checkLastClosedLedger(Overlay::PeerSequence const&, uint256& networkClosed);
+
403
+
404public:
+
405 bool
+
406 beginConsensus(
+
407 uint256 const& networkClosed,
+
408 std::unique_ptr<std::stringstream> const& clog) override;
+
409 void
+
410 endConsensus(std::unique_ptr<std::stringstream> const& clog) override;
+
411 void
+
412 setStandAlone() override;
+
413
+
417 void
+
418 setStateTimer() override;
+
419
+
420 void
+
421 setNeedNetworkLedger() override;
+
422 void
+
423 clearNeedNetworkLedger() override;
+
424 bool
+
425 isNeedNetworkLedger() override;
+
426 bool
+
427 isFull() override;
+
428
+
429 void
+
430 setMode(OperatingMode om) override;
+
431
+
432 bool
+
433 isBlocked() override;
+
434 bool
+
435 isAmendmentBlocked() override;
+
436 void
+
437 setAmendmentBlocked() override;
+
438 bool
+
439 isAmendmentWarned() override;
+
440 void
+
441 setAmendmentWarned() override;
+
442 void
+
443 clearAmendmentWarned() override;
+
444 bool
+
445 isUNLBlocked() override;
+
446 void
+
447 setUNLBlocked() override;
+
448 void
+
449 clearUNLBlocked() override;
+
450 void
+
451 consensusViewChange() override;
+
452
+
453 Json::Value
+
454 getConsensusInfo() override;
+
455 Json::Value
+
456 getServerInfo(bool human, bool admin, bool counters) override;
+
457 void
+
458 clearLedgerFetch() override;
+
459 Json::Value
+
460 getLedgerFetchInfo() override;
+
461 std::uint32_t
+
462 acceptLedger(
+
463 std::optional<std::chrono::milliseconds> consensusDelay) override;
+
464 void
+
465 reportFeeChange() override;
+
466 void
+
467 reportConsensusStateChange(ConsensusPhase phase);
+
468
+
469 void
+
470 updateLocalTx(ReadView const& view) override;
+
471 std::size_t
+
472 getLocalTxCount() override;
+
473
+
474 //
+
475 // Monitoring: publisher side.
+
476 //
+
477 void
+
478 pubLedger(std::shared_ptr<ReadView const> const& lpAccepted) override;
+
479 void
+
480 pubProposedTransaction(
+
481 std::shared_ptr<ReadView const> const& ledger,
+
482 std::shared_ptr<STTx const> const& transaction,
+
483 TER result) override;
+
484 void
+
485 pubValidation(std::shared_ptr<STValidation> const& val) override;
+
486
+
487 //--------------------------------------------------------------------------
+
488 //
+
489 // InfoSub::Source.
+
490 //
+
491 void
+
492 subAccount(
+
493 InfoSub::ref ispListener,
+
494 hash_set<AccountID> const& vnaAccountIDs,
+
495 bool rt) override;
+
496 void
+
497 unsubAccount(
+
498 InfoSub::ref ispListener,
+
499 hash_set<AccountID> const& vnaAccountIDs,
+
500 bool rt) override;
+
501
+
502 // Just remove the subscription from the tracking
+
503 // not from the InfoSub. Needed for InfoSub destruction
+
504 void
+
505 unsubAccountInternal(
+
506 std::uint64_t seq,
+
507 hash_set<AccountID> const& vnaAccountIDs,
+
508 bool rt) override;
+
509
+
510 error_code_i
+
511 subAccountHistory(InfoSub::ref ispListener, AccountID const& account)
+
512 override;
+
513 void
+
514 unsubAccountHistory(
+
515 InfoSub::ref ispListener,
+
516 AccountID const& account,
+
517 bool historyOnly) override;
+
518
+
519 void
+
520 unsubAccountHistoryInternal(
+
521 std::uint64_t seq,
+
522 AccountID const& account,
+
523 bool historyOnly) override;
+
524
+
525 bool
+
526 subLedger(InfoSub::ref ispListener, Json::Value& jvResult) override;
+
527 bool
+
528 unsubLedger(std::uint64_t uListener) override;
+
529
+
530 bool
+
531 subBookChanges(InfoSub::ref ispListener) override;
+
532 bool
+
533 unsubBookChanges(std::uint64_t uListener) override;
+
534
+
535 bool
+
536 subServer(InfoSub::ref ispListener, Json::Value& jvResult, bool admin)
+
537 override;
+
538 bool
+
539 unsubServer(std::uint64_t uListener) override;
+
540
+
541 bool
+
542 subBook(InfoSub::ref ispListener, Book const&) override;
+
543 bool
+
544 unsubBook(std::uint64_t uListener, Book const&) override;
+
545
+
546 bool
+
547 subManifests(InfoSub::ref ispListener) override;
+
548 bool
+
549 unsubManifests(std::uint64_t uListener) override;
+
550 void
+
551 pubManifest(Manifest const&) override;
+
552
+
553 bool
+
554 subTransactions(InfoSub::ref ispListener) override;
+
555 bool
+
556 unsubTransactions(std::uint64_t uListener) override;
+
557
+
558 bool
+
559 subRTTransactions(InfoSub::ref ispListener) override;
+
560 bool
+
561 unsubRTTransactions(std::uint64_t uListener) override;
+
562
+
563 bool
+
564 subValidations(InfoSub::ref ispListener) override;
+
565 bool
+
566 unsubValidations(std::uint64_t uListener) override;
+
567
+
568 bool
+
569 subPeerStatus(InfoSub::ref ispListener) override;
+
570 bool
+
571 unsubPeerStatus(std::uint64_t uListener) override;
+
572 void
+
573 pubPeerStatus(std::function<Json::Value(void)> const&) override;
+
574
+
575 bool
+
576 subConsensus(InfoSub::ref ispListener) override;
+
577 bool
+
578 unsubConsensus(std::uint64_t uListener) override;
+
579
+
580 InfoSub::pointer
+
581 findRpcSub(std::string const& strUrl) override;
+
582 InfoSub::pointer
+
583 addRpcSub(std::string const& strUrl, InfoSub::ref) override;
+
584 bool
+
585 tryRemoveRpcSub(std::string const& strUrl) override;
+
586
+
587 void
+
588 stop() override
+
589 {
+
590 {
+
591 boost::system::error_code ec;
+
592 heartbeatTimer_.cancel(ec);
+
593 if (ec)
+
594 {
+
595 JLOG(m_journal.error())
+
596 << "NetworkOPs: heartbeatTimer cancel error: "
+
597 << ec.message();
+
598 }
+
599
+
600 ec.clear();
+
601 clusterTimer_.cancel(ec);
+
602 if (ec)
+
603 {
+
604 JLOG(m_journal.error())
+
605 << "NetworkOPs: clusterTimer cancel error: "
+
606 << ec.message();
+
607 }
+
608
+
609 ec.clear();
+
610 accountHistoryTxTimer_.cancel(ec);
+
611 if (ec)
+
612 {
+
613 JLOG(m_journal.error())
+
614 << "NetworkOPs: accountHistoryTxTimer cancel error: "
+
615 << ec.message();
+
616 }
+
617 }
+
618 // Make sure that any waitHandlers pending in our timers are done.
+
619 using namespace std::chrono_literals;
+
620 waitHandlerCounter_.join("NetworkOPs", 1s, m_journal);
+
621 }
+
622
+
623 void
+
624 stateAccounting(Json::Value& obj) override;
+
625
+
626private:
+
627 void
+
628 setTimer(
+
629 boost::asio::steady_timer& timer,
+
630 std::chrono::milliseconds const& expiry_time,
+
631 std::function<void()> onExpire,
+
632 std::function<void()> onError);
+
633 void
+
634 setHeartbeatTimer();
+
635 void
+
636 setClusterTimer();
+
637 void
+
638 processHeartbeatTimer();
+
639 void
+
640 processClusterTimer();
+
641
+
642 MultiApiJson
+
643 transJson(
+
644 std::shared_ptr<STTx const> const& transaction,
+
645 TER result,
+
646 bool validated,
+
647 std::shared_ptr<ReadView const> const& ledger,
+
648 std::optional<std::reference_wrapper<TxMeta const>> meta);
+
649
+
650 void
+
651 pubValidatedTransaction(
+
652 std::shared_ptr<ReadView const> const& ledger,
+
653 AcceptedLedgerTx const& transaction,
+
654 bool last);
+
655
+
656 void
+
657 pubAccountTransaction(
+
658 std::shared_ptr<ReadView const> const& ledger,
+
659 AcceptedLedgerTx const& transaction,
+
660 bool last);
+
661
+
662 void
+
663 pubProposedAccountTransaction(
+
664 std::shared_ptr<ReadView const> const& ledger,
+
665 std::shared_ptr<STTx const> const& transaction,
+
666 TER result);
+
667
+
668 void
+
669 pubServer();
+
670 void
+
671 pubConsensus(ConsensusPhase phase);
+
672
+
673 std::string
+
674 getHostId(bool forAdmin);
+
675
+
676private:
+
677 using SubMapType = hash_map<std::uint64_t, InfoSub::wptr>;
+
678 using SubInfoMapType = hash_map<AccountID, SubMapType>;
+
679 using subRpcMapType = hash_map<std::string, InfoSub::pointer>;
+
680
+
681 /*
+
682 * With a validated ledger to separate history and future, the node
+
683 * streams historical txns with negative indexes starting from -1,
+
684 * and streams future txns starting from index 0.
+
685 * The SubAccountHistoryIndex struct maintains these indexes.
+
686 * It also has a flag stopHistorical_ for stopping streaming
+
687 * the historical txns.
+
688 */
+
689 struct SubAccountHistoryIndex
+
690 {
+
691 AccountID const accountId_;
+
692 // forward
+
693 std::uint32_t forwardTxIndex_;
+
694 // separate backward and forward
+
695 std::uint32_t separationLedgerSeq_;
+
696 // history, backward
+
697 std::uint32_t historyLastLedgerSeq_;
+
698 std::int32_t historyTxIndex_;
+
699 bool haveHistorical_;
+
700 std::atomic<bool> stopHistorical_;
+
701
+
702 SubAccountHistoryIndex(AccountID const& accountId)
+
703 : accountId_(accountId)
+
704 , forwardTxIndex_(0)
+
705 , separationLedgerSeq_(0)
+
706 , historyLastLedgerSeq_(0)
+
707 , historyTxIndex_(-1)
+
708 , haveHistorical_(false)
+
709 , stopHistorical_(false)
+
710 {
+
711 }
+
712 };
+
713 struct SubAccountHistoryInfo
+
714 {
+
715 InfoSub::pointer sink_;
+
716 std::shared_ptr<SubAccountHistoryIndex> index_;
+
717 };
+
718 struct SubAccountHistoryInfoWeak
+
719 {
+
720 InfoSub::wptr sinkWptr_;
+
721 std::shared_ptr<SubAccountHistoryIndex> index_;
+
722 };
+
723 using SubAccountHistoryMapType =
+
724 hash_map<AccountID, hash_map<std::uint64_t, SubAccountHistoryInfoWeak>>;
+
725
+
729 void
+
730 subAccountHistoryStart(
+
731 std::shared_ptr<ReadView const> const& ledger,
+
732 SubAccountHistoryInfoWeak& subInfo);
+
733 void
+
734 addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo);
+
735 void
+
736 setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo);
+
737
+
738 Application& app_;
+
739 beast::Journal m_journal;
+
740
+
741 std::unique_ptr<LocalTxs> m_localTX;
+
742
+
743 std::recursive_mutex mSubLock;
+
744
+
745 std::atomic<OperatingMode> mMode;
+
746
+
747 std::atomic<bool> needNetworkLedger_{false};
+
748 std::atomic<bool> amendmentBlocked_{false};
+
749 std::atomic<bool> amendmentWarned_{false};
+
750 std::atomic<bool> unlBlocked_{false};
+
751
+
752 ClosureCounter<void, boost::system::error_code const&> waitHandlerCounter_;
+
753 boost::asio::steady_timer heartbeatTimer_;
+
754 boost::asio::steady_timer clusterTimer_;
+
755 boost::asio::steady_timer accountHistoryTxTimer_;
+
756
+
757 RCLConsensus mConsensus;
+
758
+
759 std::optional<PublicKey> const validatorPK_;
+
760 std::optional<PublicKey> const validatorMasterPK_;
+
761
+
762 ConsensusPhase mLastConsensusPhase;
+
763
+
764 LedgerMaster& m_ledgerMaster;
+
765
+
766 SubInfoMapType mSubAccount;
+
767 SubInfoMapType mSubRTAccount;
+
768
+
769 subRpcMapType mRpcSubMap;
+
770
+
771 SubAccountHistoryMapType mSubAccountHistory;
+
772
+
773 enum SubTypes {
+
774 sLedger, // Accepted ledgers.
+
775 sManifests, // Received validator manifests.
+
776 sServer, // When server changes connectivity state.
+
777 sTransactions, // All accepted transactions.
+
778 sRTTransactions, // All proposed and accepted transactions.
+
779 sValidations, // Received validations.
+
780 sPeerStatus, // Peer status changes.
+
781 sConsensusPhase, // Consensus phase
+
782 sBookChanges, // Per-ledger order book changes
+
783 sLastEntry // Any new entry must be ADDED ABOVE this one
+
784 };
+
785
+
786 std::array<SubMapType, SubTypes::sLastEntry> mStreamMaps;
+
787
+
788 ServerFeeSummary mLastFeeSummary;
+
789
+
790 JobQueue& m_job_queue;
+
791
+
792 // Whether we are in standalone mode.
+
793 bool const m_standalone;
+
794
+
795 // The number of nodes that we need to consider ourselves connected.
+
796 std::size_t const minPeerCount_;
+
797
+
798 // Transaction batching.
+
799 std::condition_variable mCond;
+
800 std::mutex mMutex;
+
801 DispatchState mDispatchState = DispatchState::none;
+
802 std::vector<TransactionStatus> mTransactions;
+
803
+
804 StateAccounting accounting_{};
+
805
+
806 std::set<uint256> pendingValidations_;
+
807 std::mutex validationsMutex_;
+
808
+
809private:
+
810 struct Stats
+
811 {
+
812 template <class Handler>
+
813 Stats(
+
814 Handler const& handler,
+
815 beast::insight::Collector::ptr const& collector)
+
816 : hook(collector->make_hook(handler))
+
817 , disconnected_duration(collector->make_gauge(
+
818 "State_Accounting",
+
819 "Disconnected_duration"))
+
820 , connected_duration(collector->make_gauge(
+
821 "State_Accounting",
+
822 "Connected_duration"))
+
823 , syncing_duration(
+
824 collector->make_gauge("State_Accounting", "Syncing_duration"))
+
825 , tracking_duration(collector->make_gauge(
+
826 "State_Accounting",
+
827 "Tracking_duration"))
+
828 , full_duration(
+
829 collector->make_gauge("State_Accounting", "Full_duration"))
+
830 , disconnected_transitions(collector->make_gauge(
+
831 "State_Accounting",
+
832 "Disconnected_transitions"))
+
833 , connected_transitions(collector->make_gauge(
+
834 "State_Accounting",
+
835 "Connected_transitions"))
+
836 , syncing_transitions(collector->make_gauge(
+
837 "State_Accounting",
+
838 "Syncing_transitions"))
+
839 , tracking_transitions(collector->make_gauge(
+
840 "State_Accounting",
+
841 "Tracking_transitions"))
+
842 , full_transitions(
+
843 collector->make_gauge("State_Accounting", "Full_transitions"))
+
844 {
+
845 }
+
846
+
847 beast::insight::Hook hook;
+
848 beast::insight::Gauge disconnected_duration;
+
849 beast::insight::Gauge connected_duration;
+
850 beast::insight::Gauge syncing_duration;
+
851 beast::insight::Gauge tracking_duration;
+
852 beast::insight::Gauge full_duration;
+
853
+
854 beast::insight::Gauge disconnected_transitions;
+
855 beast::insight::Gauge connected_transitions;
+
856 beast::insight::Gauge syncing_transitions;
+
857 beast::insight::Gauge tracking_transitions;
+
858 beast::insight::Gauge full_transitions;
+
859 };
+
860
+
861 std::mutex m_statsMutex; // Mutex to lock m_stats
+
862 Stats m_stats;
+
863
+
864private:
+
865 void
+
866 collect_metrics();
+
867};
+
868
+
869//------------------------------------------------------------------------------
+
870
+
871static std::array<char const*, 5> const stateNames{
+
872 {"disconnected", "connected", "syncing", "tracking", "full"}};
+
873
+
874std::array<char const*, 5> const NetworkOPsImp::states_ = stateNames;
+
875
+
876std::array<Json::StaticString const, 5> const
+
877 NetworkOPsImp::StateAccounting::states_ = {
+
878 {Json::StaticString(stateNames[0]),
+
879 Json::StaticString(stateNames[1]),
+
880 Json::StaticString(stateNames[2]),
+
881 Json::StaticString(stateNames[3]),
+
882 Json::StaticString(stateNames[4])}};
+
883
+
884static auto const genesisAccountId = calcAccountID(
+
885 generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase"))
+
886 .first);
+
887
+
888//------------------------------------------------------------------------------
+
889inline OperatingMode
+
890NetworkOPsImp::getOperatingMode() const
+
891{
+
892 return mMode;
+
893}
+
894
+
895inline std::string
+
896NetworkOPsImp::strOperatingMode(bool const admin /* = false */) const
+
897{
+
898 return strOperatingMode(mMode, admin);
+
899}
+
900
+
901inline void
+
902NetworkOPsImp::setStandAlone()
+
903{
+
904 setMode(OperatingMode::FULL);
+
905}
+
906
+
907inline void
+
908NetworkOPsImp::setNeedNetworkLedger()
+
909{
+
910 needNetworkLedger_ = true;
+
911}
+
912
+
913inline void
+
914NetworkOPsImp::clearNeedNetworkLedger()
+
915{
+
916 needNetworkLedger_ = false;
+
917}
+
918
+
919inline bool
+
920NetworkOPsImp::isNeedNetworkLedger()
+
921{
+
922 return needNetworkLedger_;
+
923}
+
924
+
925inline bool
+
926NetworkOPsImp::isFull()
+
927{
+
928 return !needNetworkLedger_ && (mMode == OperatingMode::FULL);
+
929}
+
930
+
931std::string
+
932NetworkOPsImp::getHostId(bool forAdmin)
+
933{
+
934 static std::string const hostname = boost::asio::ip::host_name();
+
935
+
936 if (forAdmin)
+
937 return hostname;
+
938
+
939 // For non-admin uses hash the node public key into a
+
940 // single RFC1751 word:
+
941 static std::string const shroudedHostId = [this]() {
+
942 auto const& id = app_.nodeIdentity();
+
943
+
944 return RFC1751::getWordFromBlob(id.first.data(), id.first.size());
+
945 }();
+
946
+
947 return shroudedHostId;
+
948}
+
949
+
950void
+
951NetworkOPsImp::setStateTimer()
+
952{
+
953 setHeartbeatTimer();
+
954
+
955 // Only do this work if a cluster is configured
+
956 if (app_.cluster().size() != 0)
+
957 setClusterTimer();
+
958}
+
959
+
960void
+
961NetworkOPsImp::setTimer(
+
962 boost::asio::steady_timer& timer,
+
963 std::chrono::milliseconds const& expiry_time,
+
964 std::function<void()> onExpire,
+
965 std::function<void()> onError)
+
966{
+
967 // Only start the timer if waitHandlerCounter_ is not yet joined.
+
968 if (auto optionalCountedHandler = waitHandlerCounter_.wrap(
+
969 [this, onExpire, onError](boost::system::error_code const& e) {
+
970 if ((e.value() == boost::system::errc::success) &&
+
971 (!m_job_queue.isStopped()))
+
972 {
+
973 onExpire();
+
974 }
+
975 // Recover as best we can if an unexpected error occurs.
+
976 if (e.value() != boost::system::errc::success &&
+
977 e.value() != boost::asio::error::operation_aborted)
+
978 {
+
979 // Try again later and hope for the best.
+
980 JLOG(m_journal.error())
+
981 << "Timer got error '" << e.message()
+
982 << "'. Restarting timer.";
+
983 onError();
+
984 }
+
985 }))
+
986 {
+
987 timer.expires_from_now(expiry_time);
+
988 timer.async_wait(std::move(*optionalCountedHandler));
+
989 }
+
990}
+
991
+
992void
+
993NetworkOPsImp::setHeartbeatTimer()
+
994{
+
995 setTimer(
+
996 heartbeatTimer_,
+
997 mConsensus.parms().ledgerGRANULARITY,
+
998 [this]() {
+
999 m_job_queue.addJob(jtNETOP_TIMER, "NetOPs.heartbeat", [this]() {
+
1000 processHeartbeatTimer();
+
1001 });
+
1002 },
+
1003 [this]() { setHeartbeatTimer(); });
+
1004}
+
1005
+
1006void
+
1007NetworkOPsImp::setClusterTimer()
+
1008{
+
1009 using namespace std::chrono_literals;
+
1010
+
1011 setTimer(
+
1012 clusterTimer_,
+
1013 10s,
+
1014 [this]() {
+
1015 m_job_queue.addJob(jtNETOP_CLUSTER, "NetOPs.cluster", [this]() {
+
1016 processClusterTimer();
+
1017 });
+
1018 },
+
1019 [this]() { setClusterTimer(); });
+
1020}
+
1021
+
1022void
+
1023NetworkOPsImp::setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
+
1024{
+
1025 JLOG(m_journal.debug()) << "Scheduling AccountHistory job for account "
+
1026 << toBase58(subInfo.index_->accountId_);
+
1027 using namespace std::chrono_literals;
+
1028 setTimer(
+
1029 accountHistoryTxTimer_,
+
1030 4s,
+
1031 [this, subInfo]() { addAccountHistoryJob(subInfo); },
+
1032 [this, subInfo]() { setAccountHistoryJobTimer(subInfo); });
+
1033}
+
1034
+
1035void
+
1036NetworkOPsImp::processHeartbeatTimer()
+
1037{
+
1038 RclConsensusLogger clog(
+
1039 "Heartbeat Timer", mConsensus.validating(), m_journal);
+
1040 {
+
1041 std::unique_lock lock{app_.getMasterMutex()};
+
1042
+
1043 // VFALCO NOTE This is for diagnosing a crash on exit
+
1044 LoadManager& mgr(app_.getLoadManager());
+
1045 mgr.heartbeat();
+
1046
+
1047 std::size_t const numPeers = app_.overlay().size();
+
1048
+
1049 // do we have sufficient peers? If not, we are disconnected.
+
1050 if (numPeers < minPeerCount_)
+
1051 {
+
1052 if (mMode != OperatingMode::DISCONNECTED)
+
1053 {
+
1054 setMode(OperatingMode::DISCONNECTED);
+
1055 std::stringstream ss;
+
1056 ss << "Node count (" << numPeers << ") has fallen "
+
1057 << "below required minimum (" << minPeerCount_ << ").";
+
1058 JLOG(m_journal.warn()) << ss.str();
+
1059 CLOG(clog.ss()) << "set mode to DISCONNECTED: " << ss.str();
+
1060 }
+
1061 else
+
1062 {
+
1063 CLOG(clog.ss())
+
1064 << "already DISCONNECTED. too few peers (" << numPeers
+
1065 << "), need at least " << minPeerCount_;
+
1066 }
+
1067
+
1068 // MasterMutex lock need not be held to call setHeartbeatTimer()
+
1069 lock.unlock();
+
1070 // We do not call mConsensus.timerEntry until there are enough
+
1071 // peers providing meaningful inputs to consensus
+
1072 setHeartbeatTimer();
+
1073
+
1074 return;
+
1075 }
+
1076
+
1077 if (mMode == OperatingMode::DISCONNECTED)
+
1078 {
+
1079 setMode(OperatingMode::CONNECTED);
+
1080 JLOG(m_journal.info())
+
1081 << "Node count (" << numPeers << ") is sufficient.";
+
1082 CLOG(clog.ss()) << "setting mode to CONNECTED based on " << numPeers
+
1083 << " peers. ";
+
1084 }
+
1085
+
1086 // Check if the last validated ledger forces a change between these
+
1087 // states.
+
1088 auto origMode = mMode.load();
+
1089 CLOG(clog.ss()) << "mode: " << strOperatingMode(origMode, true);
+
1090 if (mMode == OperatingMode::SYNCING)
+
1091 setMode(OperatingMode::SYNCING);
+
1092 else if (mMode == OperatingMode::CONNECTED)
+
1093 setMode(OperatingMode::CONNECTED);
+
1094 auto newMode = mMode.load();
+
1095 if (origMode != newMode)
+
1096 {
+
1097 CLOG(clog.ss())
+
1098 << ", changing to " << strOperatingMode(newMode, true);
+
1099 }
+
1100 CLOG(clog.ss()) << ". ";
+
1101 }
+
1102
+
1103 mConsensus.timerEntry(app_.timeKeeper().closeTime(), clog.ss());
+
1104
+
1105 CLOG(clog.ss()) << "consensus phase " << to_string(mLastConsensusPhase);
+
1106 ConsensusPhase const currPhase = mConsensus.phase();
+
1107 if (mLastConsensusPhase != currPhase)
+
1108 {
+
1109 reportConsensusStateChange(currPhase);
+
1110 mLastConsensusPhase = currPhase;
+
1111 CLOG(clog.ss()) << " changed to " << to_string(mLastConsensusPhase);
+
1112 }
+
1113 CLOG(clog.ss()) << ". ";
+
1114
+
1115 setHeartbeatTimer();
+
1116}
+
1117
+
1118void
+
1119NetworkOPsImp::processClusterTimer()
+
1120{
+
1121 if (app_.cluster().size() == 0)
+
1122 return;
+
1123
+
1124 using namespace std::chrono_literals;
+
1125
+
1126 bool const update = app_.cluster().update(
+
1127 app_.nodeIdentity().first,
+
1128 "",
+
1129 (m_ledgerMaster.getValidatedLedgerAge() <= 4min)
+
1130 ? app_.getFeeTrack().getLocalFee()
+
1131 : 0,
+
1132 app_.timeKeeper().now());
+
1133
+
1134 if (!update)
+
1135 {
+
1136 JLOG(m_journal.debug()) << "Too soon to send cluster update";
+
1137 setClusterTimer();
+
1138 return;
+
1139 }
+
1140
+
1141 protocol::TMCluster cluster;
+
1142 app_.cluster().for_each([&cluster](ClusterNode const& node) {
+
1143 protocol::TMClusterNode& n = *cluster.add_clusternodes();
+
1144 n.set_publickey(toBase58(TokenType::NodePublic, node.identity()));
+
1145 n.set_reporttime(node.getReportTime().time_since_epoch().count());
+
1146 n.set_nodeload(node.getLoadFee());
+
1147 if (!node.name().empty())
+
1148 n.set_nodename(node.name());
+
1149 });
+
1150
+
1151 Resource::Gossip gossip = app_.getResourceManager().exportConsumers();
+
1152 for (auto& item : gossip.items)
+
1153 {
+
1154 protocol::TMLoadSource& node = *cluster.add_loadsources();
+
1155 node.set_name(to_string(item.address));
+
1156 node.set_cost(item.balance);
+
1157 }
+
1158 app_.overlay().foreach(send_if(
+
1159 std::make_shared<Message>(cluster, protocol::mtCLUSTER),
+
1160 peer_in_cluster()));
+
1161 setClusterTimer();
+
1162}
+
1163
+
1164//------------------------------------------------------------------------------
+
1165
+
1166std::string
+
1167NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin)
+
1168 const
+
1169{
+
1170 if (mode == OperatingMode::FULL && admin)
+
1171 {
+
1172 auto const consensusMode = mConsensus.mode();
+
1173 if (consensusMode != ConsensusMode::wrongLedger)
+
1174 {
+
1175 if (consensusMode == ConsensusMode::proposing)
+
1176 return "proposing";
+
1177
+
1178 if (mConsensus.validating())
+
1179 return "validating";
+
1180 }
+
1181 }
+
1182
+
1183 return states_[static_cast<std::size_t>(mode)];
+
1184}
+
1185
+
1186void
+
1187NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
+
1188{
+
1189 if (isNeedNetworkLedger())
+
1190 {
+
1191 // Nothing we can do if we've never been in sync
+
1192 return;
+
1193 }
+
1194
+
1195 // Enforce Network bar for batch txn
+
1196 if (iTrans->isFlag(tfInnerBatchTxn) &&
+
1197 m_ledgerMaster.getValidatedRules().enabled(featureBatch))
+
1198 {
+
1199 JLOG(m_journal.error())
+
1200 << "Submitted transaction invalid: tfInnerBatchTxn flag present.";
+
1201 return;
+
1202 }
+
1203
+
1204 // this is an asynchronous interface
+
1205 auto const trans = sterilize(*iTrans);
+
1206
+
1207 auto const txid = trans->getTransactionID();
+
1208 auto const flags = app_.getHashRouter().getFlags(txid);
+
1209
+
1210 if ((flags & SF_BAD) != 0)
+
1211 {
+
1212 JLOG(m_journal.warn()) << "Submitted transaction cached bad";
+
1213 return;
+
1214 }
+
1215
+
1216 try
+
1217 {
+
1218 auto const [validity, reason] = checkValidity(
+
1219 app_.getHashRouter(),
+
1220 *trans,
+
1221 m_ledgerMaster.getValidatedRules(),
+
1222 app_.config());
+
1223
+
1224 if (validity != Validity::Valid)
+
1225 {
+
1226 JLOG(m_journal.warn())
+
1227 << "Submitted transaction invalid: " << reason;
+
1228 return;
+
1229 }
+
1230 }
+
1231 catch (std::exception const& ex)
+
1232 {
+
1233 JLOG(m_journal.warn())
+
1234 << "Exception checking transaction " << txid << ": " << ex.what();
+
1235
+
1236 return;
+
1237 }
+
1238
+
1239 std::string reason;
+
1240
+
1241 auto tx = std::make_shared<Transaction>(trans, reason, app_);
+
1242
+
1243 m_job_queue.addJob(jtTRANSACTION, "submitTxn", [this, tx]() {
+
1244 auto t = tx;
+
1245 processTransaction(t, false, false, FailHard::no);
+
1246 });
+
1247}
+
1248
+
1249bool
+
1250NetworkOPsImp::preProcessTransaction(std::shared_ptr<Transaction>& transaction)
+
1251{
+
1252 auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
+
1253
+
1254 if ((newFlags & SF_BAD) != 0)
+
1255 {
+
1256 // cached bad
+
1257 JLOG(m_journal.warn()) << transaction->getID() << ": cached bad!\n";
+
1258 transaction->setStatus(INVALID);
+
1259 transaction->setResult(temBAD_SIGNATURE);
+
1260 return false;
+
1261 }
+
1262
+
1263 auto const view = m_ledgerMaster.getCurrentLedger();
+
1264
+
1265 // This function is called by several different parts of the codebase
+
1266 // under no circumstances will we ever accept an inner txn within a batch
+
1267 // txn from the network.
+
1268 auto const sttx = *transaction->getSTransaction();
+
1269 if (sttx.isFlag(tfInnerBatchTxn) && view->rules().enabled(featureBatch))
+
1270 {
+
1271 transaction->setStatus(INVALID);
+
1272 transaction->setResult(temINVALID_FLAG);
+
1273 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
+
1274 return false;
+
1275 }
+
1276
+
1277 // NOTE eahennis - I think this check is redundant,
+
1278 // but I'm not 100% sure yet.
+
1279 // If so, only cost is looking up HashRouter flags.
+
1280 auto const [validity, reason] =
+
1281 checkValidity(app_.getHashRouter(), sttx, view->rules(), app_.config());
+
1282 XRPL_ASSERT(
+
1283 validity == Validity::Valid,
+
1284 "ripple::NetworkOPsImp::processTransaction : valid validity");
+
1285
+
1286 // Not concerned with local checks at this point.
+
1287 if (validity == Validity::SigBad)
+
1288 {
+
1289 JLOG(m_journal.info()) << "Transaction has bad signature: " << reason;
+
1290 transaction->setStatus(INVALID);
+
1291 transaction->setResult(temBAD_SIGNATURE);
+
1292 app_.getHashRouter().setFlags(transaction->getID(), SF_BAD);
+
1293 return false;
+
1294 }
+
1295
+
1296 // canonicalize can change our pointer
+
1297 app_.getMasterTransaction().canonicalize(&transaction);
+
1298
+
1299 return true;
+
1300}
+
1301
+
1302void
+
1303NetworkOPsImp::processTransaction(
+
1304 std::shared_ptr<Transaction>& transaction,
+
1305 bool bUnlimited,
+
1306 bool bLocal,
+
1307 FailHard failType)
+
1308{
+
1309 auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXN");
+
1310
+
1311 // preProcessTransaction can change our pointer
+
1312 if (!preProcessTransaction(transaction))
+
1313 return;
+
1314
+
1315 if (bLocal)
+
1316 doTransactionSync(transaction, bUnlimited, failType);
+
1317 else
+
1318 doTransactionAsync(transaction, bUnlimited, failType);
+
1319}
+
1320
+
1321void
+
1322NetworkOPsImp::doTransactionAsync(
+
1323 std::shared_ptr<Transaction> transaction,
+
1324 bool bUnlimited,
+
1325 FailHard failType)
+
1326{
+
1327 std::lock_guard lock(mMutex);
+
1328
+
1329 if (transaction->getApplying())
+
1330 return;
+
1331
+
1332 mTransactions.push_back(
+
1333 TransactionStatus(transaction, bUnlimited, false, failType));
+
1334 transaction->setApplying();
+
1335
+
1336 if (mDispatchState == DispatchState::none)
+
1337 {
+
1338 if (m_job_queue.addJob(
+
1339 jtBATCH, "transactionBatch", [this]() { transactionBatch(); }))
+
1340 {
+
1341 mDispatchState = DispatchState::scheduled;
+
1342 }
+
1343 }
+
1344}
+
1345
+
1346void
+
1347NetworkOPsImp::doTransactionSync(
+
1348 std::shared_ptr<Transaction> transaction,
+
1349 bool bUnlimited,
+
1350 FailHard failType)
+
1351{
+
1352 std::unique_lock<std::mutex> lock(mMutex);
+
1353
+
1354 if (!transaction->getApplying())
+
1355 {
+
1356 mTransactions.push_back(
+
1357 TransactionStatus(transaction, bUnlimited, true, failType));
+
1358 transaction->setApplying();
+
1359 }
+
1360
+
1361 doTransactionSyncBatch(
+
1362 lock, [&transaction](std::unique_lock<std::mutex> const&) {
+
1363 return transaction->getApplying();
+
1364 });
+
1365}
+
1366
+
1367void
+
1368NetworkOPsImp::doTransactionSyncBatch(
+
1369 std::unique_lock<std::mutex>& lock,
+
1370 std::function<bool(std::unique_lock<std::mutex> const&)> retryCallback)
+
1371{
+
1372 do
+
1373 {
+
1374 if (mDispatchState == DispatchState::running)
+
1375 {
+
1376 // A batch processing job is already running, so wait.
+
1377 mCond.wait(lock);
+
1378 }
+
1379 else
+
1380 {
+
1381 apply(lock);
+
1382
+
1383 if (mTransactions.size())
+
1384 {
+
1385 // More transactions need to be applied, but by another job.
+
1386 if (m_job_queue.addJob(jtBATCH, "transactionBatch", [this]() {
+
1387 transactionBatch();
+
1388 }))
+
1389 {
+
1390 mDispatchState = DispatchState::scheduled;
+
1391 }
+
1392 }
+
1393 }
+
1394 } while (retryCallback(lock));
+
1395}
+
1396
+
1397void
+
1398NetworkOPsImp::processTransactionSet(CanonicalTXSet const& set)
+
1399{
+
1400 auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXNSet");
+
1401 std::vector<std::shared_ptr<Transaction>> candidates;
+
1402 candidates.reserve(set.size());
+
1403 for (auto const& [_, tx] : set)
+
1404 {
+
1405 std::string reason;
+
1406 auto transaction = std::make_shared<Transaction>(tx, reason, app_);
+
1407
+
1408 if (transaction->getStatus() == INVALID)
+
1409 {
+
1410 if (!reason.empty())
+
1411 {
+
1412 JLOG(m_journal.trace())
+
1413 << "Exception checking transaction: " << reason;
+
1414 }
+
1415 app_.getHashRouter().setFlags(tx->getTransactionID(), SF_BAD);
+
1416 continue;
+
1417 }
+
1418
+
1419 // preProcessTransaction can change our pointer
+
1420 if (!preProcessTransaction(transaction))
+
1421 continue;
+
1422
+
1423 candidates.emplace_back(transaction);
+
1424 }
+
1425
+
1426 std::vector<TransactionStatus> transactions;
+
1427 transactions.reserve(candidates.size());
+
1428
+
1429 std::unique_lock lock(mMutex);
+
1430
+
1431 for (auto& transaction : candidates)
+
1432 {
+
1433 if (!transaction->getApplying())
+
1434 {
+
1435 transactions.emplace_back(transaction, false, false, FailHard::no);
+
1436 transaction->setApplying();
+
1437 }
+
1438 }
+
1439
+
1440 if (mTransactions.empty())
+
1441 mTransactions.swap(transactions);
+
1442 else
+
1443 {
+
1444 mTransactions.reserve(mTransactions.size() + transactions.size());
+
1445 for (auto& t : transactions)
+
1446 mTransactions.push_back(std::move(t));
+
1447 }
+
1448
+
1449 doTransactionSyncBatch(lock, [&](std::unique_lock<std::mutex> const&) {
+
1450 XRPL_ASSERT(
+
1451 lock.owns_lock(),
+
1452 "ripple::NetworkOPsImp::processTransactionSet has lock");
+
1453 return std::any_of(
+
1454 mTransactions.begin(), mTransactions.end(), [](auto const& t) {
+
1455 return t.transaction->getApplying();
+
1456 });
+
1457 });
+
1458}
+
1459
+
1460void
+
1461NetworkOPsImp::transactionBatch()
+
1462{
+
1463 std::unique_lock<std::mutex> lock(mMutex);
+
1464
+
1465 if (mDispatchState == DispatchState::running)
+
1466 return;
+
1467
+
1468 while (mTransactions.size())
+
1469 {
+
1470 apply(lock);
+
1471 }
+
1472}
+
1473
+
1474void
+
1475NetworkOPsImp::apply(std::unique_lock<std::mutex>& batchLock)
+
1476{
+
1477 std::vector<TransactionStatus> submit_held;
+
1478 std::vector<TransactionStatus> transactions;
+
1479 mTransactions.swap(transactions);
+
1480 XRPL_ASSERT(
+
1481 !transactions.empty(),
+
1482 "ripple::NetworkOPsImp::apply : non-empty transactions");
+
1483 XRPL_ASSERT(
+
1484 mDispatchState != DispatchState::running,
+
1485 "ripple::NetworkOPsImp::apply : is not running");
+
1486
+
1487 mDispatchState = DispatchState::running;
+
1488
+
1489 batchLock.unlock();
+
1490
+
1491 {
+
1492 std::unique_lock masterLock{app_.getMasterMutex(), std::defer_lock};
+
1493 bool changed = false;
+
1494 {
+
1495 std::unique_lock ledgerLock{
+
1496 m_ledgerMaster.peekMutex(), std::defer_lock};
+
1497 std::lock(masterLock, ledgerLock);
+
1498
+
1499 app_.openLedger().modify([&](OpenView& view, beast::Journal j) {
+
1500 for (TransactionStatus& e : transactions)
+
1501 {
+
1502 // we check before adding to the batch
+
1503 ApplyFlags flags = tapNONE;
+
1504 if (e.admin)
+
1505 flags |= tapUNLIMITED;
+
1506
+
1507 if (e.failType == FailHard::yes)
+
1508 flags |= tapFAIL_HARD;
+
1509
+
1510 auto const result = app_.getTxQ().apply(
+
1511 app_, view, e.transaction->getSTransaction(), flags, j);
+
1512 e.result = result.ter;
+
1513 e.applied = result.applied;
+
1514 changed = changed || result.applied;
+
1515 }
+
1516 return changed;
+
1517 });
+
1518 }
+
1519 if (changed)
+
1520 reportFeeChange();
+
1521
+
1522 std::optional<LedgerIndex> validatedLedgerIndex;
+
1523 if (auto const l = m_ledgerMaster.getValidatedLedger())
+
1524 validatedLedgerIndex = l->info().seq;
+
1525
+
1526 auto newOL = app_.openLedger().current();
+
1527 for (TransactionStatus& e : transactions)
+
1528 {
+
1529 e.transaction->clearSubmitResult();
+
1530
+
1531 if (e.applied)
+
1532 {
+
1533 pubProposedTransaction(
+
1534 newOL, e.transaction->getSTransaction(), e.result);
+
1535 e.transaction->setApplied();
+
1536 }
+
1537
+
1538 e.transaction->setResult(e.result);
+
1539
+
1540 if (isTemMalformed(e.result))
+
1541 app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
+
1542
+
1543#ifdef DEBUG
+
1544 if (e.result != tesSUCCESS)
+
1545 {
+
1546 std::string token, human;
+
1547
+
1548 if (transResultInfo(e.result, token, human))
+
1549 {
+
1550 JLOG(m_journal.info())
+
1551 << "TransactionResult: " << token << ": " << human;
+
1552 }
+
1553 }
+
1554#endif
+
1555
+
1556 bool addLocal = e.local;
+
1557
+
1558 if (e.result == tesSUCCESS)
+
1559 {
+
1560 JLOG(m_journal.debug())
+
1561 << "Transaction is now included in open ledger";
+
1562 e.transaction->setStatus(INCLUDED);
+
1563
+
1564 // Pop as many "reasonable" transactions for this account as
+
1565 // possible. "Reasonable" means they have sequential sequence
+
1566 // numbers, or use tickets.
+
1567 auto const& txCur = e.transaction->getSTransaction();
+
1568
+
1569 std::size_t count = 0;
+
1570 for (auto txNext = m_ledgerMaster.popAcctTransaction(txCur);
+
1571 txNext && count < maxPoppedTransactions;
+
1572 txNext = m_ledgerMaster.popAcctTransaction(txCur), ++count)
+
1573 {
+
1574 if (!batchLock.owns_lock())
+
1575 batchLock.lock();
+
1576 std::string reason;
+
1577 auto const trans = sterilize(*txNext);
+
1578 auto t = std::make_shared<Transaction>(trans, reason, app_);
+
1579 if (t->getApplying())
+
1580 break;
+
1581 submit_held.emplace_back(t, false, false, FailHard::no);
+
1582 t->setApplying();
+
1583 }
+
1584 if (batchLock.owns_lock())
+
1585 batchLock.unlock();
+
1586 }
+
1587 else if (e.result == tefPAST_SEQ)
+
1588 {
+
1589 // duplicate or conflict
+
1590 JLOG(m_journal.info()) << "Transaction is obsolete";
+
1591 e.transaction->setStatus(OBSOLETE);
+
1592 }
+
1593 else if (e.result == terQUEUED)
+
1594 {
+
1595 JLOG(m_journal.debug())
+
1596 << "Transaction is likely to claim a"
+
1597 << " fee, but is queued until fee drops";
+
1598
+
1599 e.transaction->setStatus(HELD);
+
1600 // Add to held transactions, because it could get
+
1601 // kicked out of the queue, and this will try to
+
1602 // put it back.
+
1603 m_ledgerMaster.addHeldTransaction(e.transaction);
+
1604 e.transaction->setQueued();
+
1605 e.transaction->setKept();
+
1606 }
+
1607 else if (
+
1608 isTerRetry(e.result) || isTelLocal(e.result) ||
+
1609 isTefFailure(e.result))
+
1610 {
+
1611 if (e.failType != FailHard::yes)
+
1612 {
+
1613 auto const lastLedgerSeq =
+
1614 e.transaction->getSTransaction()->at(
+
1615 ~sfLastLedgerSequence);
+
1616 auto const ledgersLeft = lastLedgerSeq
+
1617 ? *lastLedgerSeq -
+
1618 m_ledgerMaster.getCurrentLedgerIndex()
+
1619 : std::optional<LedgerIndex>{};
+
1620 // If any of these conditions are met, the transaction can
+
1621 // be held:
+
1622 // 1. It was submitted locally. (Note that this flag is only
+
1623 // true on the initial submission.)
+
1624 // 2. The transaction has a LastLedgerSequence, and the
+
1625 // LastLedgerSequence is fewer than LocalTxs::holdLedgers
+
1626 // (5) ledgers into the future. (Remember that an
+
1627 // unseated optional compares as less than all seated
+
1628 // values, so it has to be checked explicitly first.)
+
1629 // 3. The SF_HELD flag is not set on the txID. (setFlags
+
1630 // checks before setting. If the flag is set, it returns
+
1631 // false, which means it's been held once without one of
+
1632 // the other conditions, so don't hold it again. Time's
+
1633 // up!)
+
1634 //
+
1635 if (e.local ||
+
1636 (ledgersLeft && ledgersLeft <= LocalTxs::holdLedgers) ||
+
1637 app_.getHashRouter().setFlags(
+
1638 e.transaction->getID(), SF_HELD))
+
1639 {
+
1640 // transaction should be held
+
1641 JLOG(m_journal.debug())
+
1642 << "Transaction should be held: " << e.result;
+
1643 e.transaction->setStatus(HELD);
+
1644 m_ledgerMaster.addHeldTransaction(e.transaction);
+
1645 e.transaction->setKept();
+
1646 }
+
1647 else
+
1648 JLOG(m_journal.debug())
+
1649 << "Not holding transaction "
+
1650 << e.transaction->getID() << ": "
+
1651 << (e.local ? "local" : "network") << ", "
+
1652 << "result: " << e.result << " ledgers left: "
+
1653 << (ledgersLeft ? to_string(*ledgersLeft)
+
1654 : "unspecified");
+
1655 }
+
1656 }
+
1657 else
+
1658 {
+
1659 JLOG(m_journal.debug())
+
1660 << "Status other than success " << e.result;
+
1661 e.transaction->setStatus(INVALID);
+
1662 }
+
1663
+
1664 auto const enforceFailHard =
+
1665 e.failType == FailHard::yes && !isTesSuccess(e.result);
+
1666
+
1667 if (addLocal && !enforceFailHard)
+
1668 {
+
1669 m_localTX->push_back(
+
1670 m_ledgerMaster.getCurrentLedgerIndex(),
+
1671 e.transaction->getSTransaction());
+
1672 e.transaction->setKept();
+
1673 }
+
1674
+
1675 if ((e.applied ||
+
1676 ((mMode != OperatingMode::FULL) &&
+
1677 (e.failType != FailHard::yes) && e.local) ||
+
1678 (e.result == terQUEUED)) &&
+
1679 !enforceFailHard)
+
1680 {
+
1681 auto const toSkip =
+
1682 app_.getHashRouter().shouldRelay(e.transaction->getID());
+
1683 if (auto const sttx = *(e.transaction->getSTransaction());
+
1684 toSkip &&
+
1685 // Skip relaying if it's an inner batch txn and batch
+
1686 // feature is enabled
+
1687 !(sttx.isFlag(tfInnerBatchTxn) &&
+
1688 newOL->rules().enabled(featureBatch)))
+
1689 {
+
1690 protocol::TMTransaction tx;
+
1691 Serializer s;
+
1692
+
1693 sttx.add(s);
+
1694 tx.set_rawtransaction(s.data(), s.size());
+
1695 tx.set_status(protocol::tsCURRENT);
+
1696 tx.set_receivetimestamp(
+
1697 app_.timeKeeper().now().time_since_epoch().count());
+
1698 tx.set_deferred(e.result == terQUEUED);
+
1699 // FIXME: This should be when we received it
+
1700 app_.overlay().relay(e.transaction->getID(), tx, *toSkip);
+
1701 e.transaction->setBroadcast();
+
1702 }
+
1703 }
+
1704
+
1705 if (validatedLedgerIndex)
+
1706 {
+
1707 auto [fee, accountSeq, availableSeq] =
+
1708 app_.getTxQ().getTxRequiredFeeAndSeq(
+
1709 *newOL, e.transaction->getSTransaction());
+
1710 e.transaction->setCurrentLedgerState(
+
1711 *validatedLedgerIndex, fee, accountSeq, availableSeq);
+
1712 }
+
1713 }
+
1714 }
+
1715
+
1716 batchLock.lock();
+
1717
+
1718 for (TransactionStatus& e : transactions)
+
1719 e.transaction->clearApplying();
+
1720
+
1721 if (!submit_held.empty())
+
1722 {
+
1723 if (mTransactions.empty())
+
1724 mTransactions.swap(submit_held);
+
1725 else
+
1726 {
+
1727 mTransactions.reserve(mTransactions.size() + submit_held.size());
+
1728 for (auto& e : submit_held)
+
1729 mTransactions.push_back(std::move(e));
+
1730 }
+
1731 }
+
1732
+
1733 mCond.notify_all();
+
1734
+
1735 mDispatchState = DispatchState::none;
+
1736}
+
1737
+
1738//
+
1739// Owner functions
+
1740//
+
1741
+
1742Json::Value
+
1743NetworkOPsImp::getOwnerInfo(
+
1744 std::shared_ptr<ReadView const> lpLedger,
+
1745 AccountID const& account)
+
1746{
+
1747 Json::Value jvObjects(Json::objectValue);
+
1748 auto root = keylet::ownerDir(account);
+
1749 auto sleNode = lpLedger->read(keylet::page(root));
+
1750 if (sleNode)
+
1751 {
+
1752 std::uint64_t uNodeDir;
+
1753
+
1754 do
+
1755 {
+
1756 for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes))
+
1757 {
+
1758 auto sleCur = lpLedger->read(keylet::child(uDirEntry));
+
1759 XRPL_ASSERT(
+
1760 sleCur,
+
1761 "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE");
+
1762
+
1763 switch (sleCur->getType())
+
1764 {
+
1765 case ltOFFER:
+
1766 if (!jvObjects.isMember(jss::offers))
+
1767 jvObjects[jss::offers] =
+
1768 Json::Value(Json::arrayValue);
+
1769
+
1770 jvObjects[jss::offers].append(
+
1771 sleCur->getJson(JsonOptions::none));
+
1772 break;
+
1773
+
1774 case ltRIPPLE_STATE:
+
1775 if (!jvObjects.isMember(jss::ripple_lines))
+
1776 {
+
1777 jvObjects[jss::ripple_lines] =
+
1778 Json::Value(Json::arrayValue);
+
1779 }
+
1780
+
1781 jvObjects[jss::ripple_lines].append(
+
1782 sleCur->getJson(JsonOptions::none));
+
1783 break;
+
1784
+
1785 case ltACCOUNT_ROOT:
+
1786 case ltDIR_NODE:
+
1787 default:
+
1788 UNREACHABLE(
+
1789 "ripple::NetworkOPsImp::getOwnerInfo : invalid "
+
1790 "type");
+
1791 break;
+
1792 }
+
1793 }
+
1794
+
1795 uNodeDir = sleNode->getFieldU64(sfIndexNext);
+
1796
+
1797 if (uNodeDir)
+
1798 {
+
1799 sleNode = lpLedger->read(keylet::page(root, uNodeDir));
+
1800 XRPL_ASSERT(
+
1801 sleNode,
+
1802 "ripple::NetworkOPsImp::getOwnerInfo : read next page");
+
1803 }
+
1804 } while (uNodeDir);
+
1805 }
+
1806
+
1807 return jvObjects;
+
1808}
+
1809
+
1810//
+
1811// Other
+
1812//
+
1813
+
1814inline bool
+
1815NetworkOPsImp::isBlocked()
+
1816{
+
1817 return isAmendmentBlocked() || isUNLBlocked();
+
1818}
+
1819
+
1820inline bool
+
1821NetworkOPsImp::isAmendmentBlocked()
+
1822{
+
1823 return amendmentBlocked_;
+
1824}
+
1825
+
1826void
+
1827NetworkOPsImp::setAmendmentBlocked()
+
1828{
+
1829 amendmentBlocked_ = true;
+
1830 setMode(OperatingMode::CONNECTED);
+
1831}
+
1832
+
1833inline bool
+
1834NetworkOPsImp::isAmendmentWarned()
+
1835{
+
1836 return !amendmentBlocked_ && amendmentWarned_;
+
1837}
+
1838
+
1839inline void
+
1840NetworkOPsImp::setAmendmentWarned()
+
1841{
+
1842 amendmentWarned_ = true;
+
1843}
+
1844
+
1845inline void
+
1846NetworkOPsImp::clearAmendmentWarned()
+
1847{
+
1848 amendmentWarned_ = false;
+
1849}
+
1850
+
1851inline bool
+
1852NetworkOPsImp::isUNLBlocked()
+
1853{
+
1854 return unlBlocked_;
+
1855}
+
1856
+
1857void
+
1858NetworkOPsImp::setUNLBlocked()
+
1859{
+
1860 unlBlocked_ = true;
+
1861 setMode(OperatingMode::CONNECTED);
+
1862}
+
1863
+
1864inline void
+
1865NetworkOPsImp::clearUNLBlocked()
+
1866{
+
1867 unlBlocked_ = false;
+
1868}
+
1869
+
1870bool
+
1871NetworkOPsImp::checkLastClosedLedger(
+
1872 Overlay::PeerSequence const& peerList,
+
1873 uint256& networkClosed)
+
1874{
+
1875 // Returns true if there's an *abnormal* ledger issue, normal changing in
+
1876 // TRACKING mode should return false. Do we have sufficient validations for
+
1877 // our last closed ledger? Or do sufficient nodes agree? And do we have no
+
1878 // better ledger available? If so, we are either tracking or full.
+
1879
+
1880 JLOG(m_journal.trace()) << "NetworkOPsImp::checkLastClosedLedger";
+
1881
+
1882 auto const ourClosed = m_ledgerMaster.getClosedLedger();
+
1883
+
1884 if (!ourClosed)
+
1885 return false;
+
1886
+
1887 uint256 closedLedger = ourClosed->info().hash;
+
1888 uint256 prevClosedLedger = ourClosed->info().parentHash;
+
1889 JLOG(m_journal.trace()) << "OurClosed: " << closedLedger;
+
1890 JLOG(m_journal.trace()) << "PrevClosed: " << prevClosedLedger;
+
1891
+
1892 //-------------------------------------------------------------------------
+
1893 // Determine preferred last closed ledger
+
1894
+
1895 auto& validations = app_.getValidations();
+
1896 JLOG(m_journal.debug())
+
1897 << "ValidationTrie " << Json::Compact(validations.getJsonTrie());
+
1898
+
1899 // Will rely on peer LCL if no trusted validations exist
+
1900 hash_map<uint256, std::uint32_t> peerCounts;
+
1901 peerCounts[closedLedger] = 0;
+
1902 if (mMode >= OperatingMode::TRACKING)
+
1903 peerCounts[closedLedger]++;
+
1904
+
1905 for (auto& peer : peerList)
+
1906 {
+
1907 uint256 peerLedger = peer->getClosedLedgerHash();
+
1908
+
1909 if (peerLedger.isNonZero())
+
1910 ++peerCounts[peerLedger];
+
1911 }
+
1912
+
1913 for (auto const& it : peerCounts)
+
1914 JLOG(m_journal.debug()) << "L: " << it.first << " n=" << it.second;
+
1915
+
1916 uint256 preferredLCL = validations.getPreferredLCL(
+
1917 RCLValidatedLedger{ourClosed, validations.adaptor().journal()},
+
1918 m_ledgerMaster.getValidLedgerIndex(),
+
1919 peerCounts);
+
1920
+
1921 bool switchLedgers = preferredLCL != closedLedger;
+
1922 if (switchLedgers)
+
1923 closedLedger = preferredLCL;
+
1924 //-------------------------------------------------------------------------
+
1925 if (switchLedgers && (closedLedger == prevClosedLedger))
+
1926 {
+
1927 // don't switch to our own previous ledger
+
1928 JLOG(m_journal.info()) << "We won't switch to our own previous ledger";
+
1929 networkClosed = ourClosed->info().hash;
+
1930 switchLedgers = false;
+
1931 }
+
1932 else
+
1933 networkClosed = closedLedger;
+
1934
+
1935 if (!switchLedgers)
+
1936 return false;
+
1937
+
1938 auto consensus = m_ledgerMaster.getLedgerByHash(closedLedger);
+
1939
+
1940 if (!consensus)
+
1941 consensus = app_.getInboundLedgers().acquire(
+
1942 closedLedger, 0, InboundLedger::Reason::CONSENSUS);
+
1943
+
1944 if (consensus &&
+
1945 (!m_ledgerMaster.canBeCurrent(consensus) ||
+
1946 !m_ledgerMaster.isCompatible(
+
1947 *consensus, m_journal.debug(), "Not switching")))
+
1948 {
+
1949 // Don't switch to a ledger not on the validated chain
+
1950 // or with an invalid close time or sequence
+
1951 networkClosed = ourClosed->info().hash;
+
1952 return false;
+
1953 }
+
1954
+
1955 JLOG(m_journal.warn()) << "We are not running on the consensus ledger";
+
1956 JLOG(m_journal.info()) << "Our LCL: " << ourClosed->info().hash
+
1957 << getJson({*ourClosed, {}});
+
1958 JLOG(m_journal.info()) << "Net LCL " << closedLedger;
+
1959
+
1960 if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
+
1961 {
+
1962 setMode(OperatingMode::CONNECTED);
+
1963 }
+
1964
+
1965 if (consensus)
+
1966 {
+
1967 // FIXME: If this rewinds the ledger sequence, or has the same
+
1968 // sequence, we should update the status on any stored transactions
+
1969 // in the invalidated ledgers.
+
1970 switchLastClosedLedger(consensus);
+
1971 }
+
1972
+
1973 return true;
+
1974}
+
1975
+
1976void
+
1977NetworkOPsImp::switchLastClosedLedger(
+
1978 std::shared_ptr<Ledger const> const& newLCL)
+
1979{
+
1980 // set the newLCL as our last closed ledger -- this is abnormal code
+
1981 JLOG(m_journal.error())
+
1982 << "JUMP last closed ledger to " << newLCL->info().hash;
+
1983
+
1984 clearNeedNetworkLedger();
+
1985
+
1986 // Update fee computations.
+
1987 app_.getTxQ().processClosedLedger(app_, *newLCL, true);
+
1988
+
1989 // Caller must own master lock
+
1990 {
+
1991 // Apply tx in old open ledger to new
+
1992 // open ledger. Then apply local tx.
+
1993
+
1994 auto retries = m_localTX->getTxSet();
+
1995 auto const lastVal = app_.getLedgerMaster().getValidatedLedger();
+
1996 std::optional<Rules> rules;
+
1997 if (lastVal)
+
1998 rules = makeRulesGivenLedger(*lastVal, app_.config().features);
+
1999 else
+
2000 rules.emplace(app_.config().features);
+
2001 app_.openLedger().accept(
+
2002 app_,
+
2003 *rules,
+
2004 newLCL,
+
2005 OrderedTxs({}),
+
2006 false,
+
2007 retries,
+
2008 tapNONE,
+
2009 "jump",
+
2010 [&](OpenView& view, beast::Journal j) {
+
2011 // Stuff the ledger with transactions from the queue.
+
2012 return app_.getTxQ().accept(app_, view);
+
2013 });
+
2014 }
+
2015
+
2016 m_ledgerMaster.switchLCL(newLCL);
+
2017
+
2018 protocol::TMStatusChange s;
+
2019 s.set_newevent(protocol::neSWITCHED_LEDGER);
+
2020 s.set_ledgerseq(newLCL->info().seq);
+
2021 s.set_networktime(app_.timeKeeper().now().time_since_epoch().count());
+
2022 s.set_ledgerhashprevious(
+
2023 newLCL->info().parentHash.begin(), newLCL->info().parentHash.size());
+
2024 s.set_ledgerhash(newLCL->info().hash.begin(), newLCL->info().hash.size());
+
2025
+
2026 app_.overlay().foreach(
+
2027 send_always(std::make_shared<Message>(s, protocol::mtSTATUS_CHANGE)));
+
2028}
+
2029
+
2030bool
+
2031NetworkOPsImp::beginConsensus(
+
2032 uint256 const& networkClosed,
+
2033 std::unique_ptr<std::stringstream> const& clog)
+
2034{
+
2035 XRPL_ASSERT(
+
2036 networkClosed.isNonZero(),
+
2037 "ripple::NetworkOPsImp::beginConsensus : nonzero input");
+
2038
+
2039 auto closingInfo = m_ledgerMaster.getCurrentLedger()->info();
+
2040
+
2041 JLOG(m_journal.info()) << "Consensus time for #" << closingInfo.seq
+
2042 << " with LCL " << closingInfo.parentHash;
+
2043
+
2044 auto prevLedger = m_ledgerMaster.getLedgerByHash(closingInfo.parentHash);
+
2045
+
2046 if (!prevLedger)
+
2047 {
+
2048 // this shouldn't happen unless we jump ledgers
+
2049 if (mMode == OperatingMode::FULL)
+
2050 {
+
2051 JLOG(m_journal.warn()) << "Don't have LCL, going to tracking";
+
2052 setMode(OperatingMode::TRACKING);
+
2053 CLOG(clog) << "beginConsensus Don't have LCL, going to tracking. ";
+
2054 }
+
2055
+
2056 CLOG(clog) << "beginConsensus no previous ledger. ";
+
2057 return false;
+
2058 }
+
2059
+
2060 XRPL_ASSERT(
+
2061 prevLedger->info().hash == closingInfo.parentHash,
+
2062 "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches "
+
2063 "parent");
+
2064 XRPL_ASSERT(
+
2065 closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash,
+
2066 "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches "
+
2067 "hash");
+
2068
+
2069 if (prevLedger->rules().enabled(featureNegativeUNL))
+
2070 app_.validators().setNegativeUNL(prevLedger->negativeUNL());
+
2071 TrustChanges const changes = app_.validators().updateTrusted(
+
2072 app_.getValidations().getCurrentNodeIDs(),
+
2073 closingInfo.parentCloseTime,
+
2074 *this,
+
2075 app_.overlay(),
+
2076 app_.getHashRouter());
+
2077
+
2078 if (!changes.added.empty() || !changes.removed.empty())
+
2079 {
+
2080 app_.getValidations().trustChanged(changes.added, changes.removed);
+
2081 // Update the AmendmentTable so it tracks the current validators.
+
2082 app_.getAmendmentTable().trustChanged(
+
2083 app_.validators().getQuorumKeys().second);
+
2084 }
+
2085
+
2086 mConsensus.startRound(
+
2087 app_.timeKeeper().closeTime(),
+
2088 networkClosed,
+
2089 prevLedger,
+
2090 changes.removed,
+
2091 changes.added,
+
2092 clog);
+
2093
+
2094 ConsensusPhase const currPhase = mConsensus.phase();
+
2095 if (mLastConsensusPhase != currPhase)
+
2096 {
+
2097 reportConsensusStateChange(currPhase);
+
2098 mLastConsensusPhase = currPhase;
+
2099 }
+
2100
+
2101 JLOG(m_journal.debug()) << "Initiating consensus engine";
+
2102 return true;
+
2103}
+
2104
+
2105bool
+
2106NetworkOPsImp::processTrustedProposal(RCLCxPeerPos peerPos)
+
2107{
+
2108 auto const& peerKey = peerPos.publicKey();
+
2109 if (validatorPK_ == peerKey || validatorMasterPK_ == peerKey)
+
2110 {
+
2111 // Could indicate a operator misconfiguration where two nodes are
+
2112 // running with the same validator key configured, so this isn't fatal,
+
2113 // and it doesn't necessarily indicate peer misbehavior. But since this
+
2114 // is a trusted message, it could be a very big deal. Either way, we
+
2115 // don't want to relay the proposal. Note that the byzantine behavior
+
2116 // detection in handleNewValidation will notify other peers.
+
2117 //
+
2118 // Another, innocuous explanation is unusual message routing and delays,
+
2119 // causing this node to receive its own messages back.
+
2120 JLOG(m_journal.error())
+
2121 << "Received a proposal signed by MY KEY from a peer. This may "
+
2122 "indicate a misconfiguration where another node has the same "
+
2123 "validator key, or may be caused by unusual message routing and "
+
2124 "delays.";
+
2125 return false;
+
2126 }
+
2127
+
2128 return mConsensus.peerProposal(app_.timeKeeper().closeTime(), peerPos);
+
2129}
+
2130
+
2131void
+
2132NetworkOPsImp::mapComplete(std::shared_ptr<SHAMap> const& map, bool fromAcquire)
+
2133{
+
2134 // We now have an additional transaction set
+
2135 // either created locally during the consensus process
+
2136 // or acquired from a peer
+
2137
+
2138 // Inform peers we have this set
+
2139 protocol::TMHaveTransactionSet msg;
+
2140 msg.set_hash(map->getHash().as_uint256().begin(), 256 / 8);
+
2141 msg.set_status(protocol::tsHAVE);
+
2142 app_.overlay().foreach(
+
2143 send_always(std::make_shared<Message>(msg, protocol::mtHAVE_SET)));
+
2144
+
2145 // We acquired it because consensus asked us to
+
2146 if (fromAcquire)
+
2147 mConsensus.gotTxSet(app_.timeKeeper().closeTime(), RCLTxSet{map});
+
2148}
+
2149
+
2150void
+
2151NetworkOPsImp::endConsensus(std::unique_ptr<std::stringstream> const& clog)
+
2152{
+
2153 uint256 deadLedger = m_ledgerMaster.getClosedLedger()->info().parentHash;
+
2154
+
2155 for (auto const& it : app_.overlay().getActivePeers())
+
2156 {
+
2157 if (it && (it->getClosedLedgerHash() == deadLedger))
+
2158 {
+
2159 JLOG(m_journal.trace()) << "Killing obsolete peer status";
+
2160 it->cycleStatus();
+
2161 }
+
2162 }
+
2163
+
2164 uint256 networkClosed;
+
2165 bool ledgerChange =
+
2166 checkLastClosedLedger(app_.overlay().getActivePeers(), networkClosed);
+
2167
+
2168 if (networkClosed.isZero())
+
2169 {
+
2170 CLOG(clog) << "endConsensus last closed ledger is zero. ";
+
2171 return;
+
2172 }
+
2173
+
2174 // WRITEME: Unless we are in FULL and in the process of doing a consensus,
+
2175 // we must count how many nodes share our LCL, how many nodes disagree with
+
2176 // our LCL, and how many validations our LCL has. We also want to check
+
2177 // timing to make sure there shouldn't be a newer LCL. We need this
+
2178 // information to do the next three tests.
+
2179
+
2180 if (((mMode == OperatingMode::CONNECTED) ||
+
2181 (mMode == OperatingMode::SYNCING)) &&
+
2182 !ledgerChange)
+
2183 {
+
2184 // Count number of peers that agree with us and UNL nodes whose
+
2185 // validations we have for LCL. If the ledger is good enough, go to
+
2186 // TRACKING - TODO
+
2187 if (!needNetworkLedger_)
+
2188 setMode(OperatingMode::TRACKING);
+
2189 }
+
2190
+
2191 if (((mMode == OperatingMode::CONNECTED) ||
+
2192 (mMode == OperatingMode::TRACKING)) &&
+
2193 !ledgerChange)
+
2194 {
+
2195 // check if the ledger is good enough to go to FULL
+
2196 // Note: Do not go to FULL if we don't have the previous ledger
+
2197 // check if the ledger is bad enough to go to CONNECTE D -- TODO
+
2198 auto current = m_ledgerMaster.getCurrentLedger();
+
2199 if (app_.timeKeeper().now() < (current->info().parentCloseTime +
+
2200 2 * current->info().closeTimeResolution))
+
2201 {
+
2202 setMode(OperatingMode::FULL);
+
2203 }
+
2204 }
+
2205
+
2206 beginConsensus(networkClosed, clog);
+
2207}
+
2208
+
2209void
+
2210NetworkOPsImp::consensusViewChange()
+
2211{
+
2212 if ((mMode == OperatingMode::FULL) || (mMode == OperatingMode::TRACKING))
+
2213 {
+
2214 setMode(OperatingMode::CONNECTED);
+
2215 }
+
2216}
+
2217
+
2218void
+
2219NetworkOPsImp::pubManifest(Manifest const& mo)
+
2220{
+
2221 // VFALCO consider std::shared_mutex
+
2222 std::lock_guard sl(mSubLock);
+
2223
+
2224 if (!mStreamMaps[sManifests].empty())
+
2225 {
+
2226 Json::Value jvObj(Json::objectValue);
+
2227
+
2228 jvObj[jss::type] = "manifestReceived";
+
2229 jvObj[jss::master_key] = toBase58(TokenType::NodePublic, mo.masterKey);
+
2230 if (mo.signingKey)
+
2231 jvObj[jss::signing_key] =
+
2232 toBase58(TokenType::NodePublic, *mo.signingKey);
+
2233 jvObj[jss::seq] = Json::UInt(mo.sequence);
+
2234 if (auto sig = mo.getSignature())
+
2235 jvObj[jss::signature] = strHex(*sig);
+
2236 jvObj[jss::master_signature] = strHex(mo.getMasterSignature());
+
2237 if (!mo.domain.empty())
+
2238 jvObj[jss::domain] = mo.domain;
+
2239 jvObj[jss::manifest] = strHex(mo.serialized);
+
2240
+
2241 for (auto i = mStreamMaps[sManifests].begin();
+
2242 i != mStreamMaps[sManifests].end();)
+
2243 {
+
2244 if (auto p = i->second.lock())
+
2245 {
+
2246 p->send(jvObj, true);
+
2247 ++i;
+
2248 }
+
2249 else
+
2250 {
+
2251 i = mStreamMaps[sManifests].erase(i);
+
2252 }
+
2253 }
+
2254 }
+
2255}
+
2256
+
2257NetworkOPsImp::ServerFeeSummary::ServerFeeSummary(
+
2258 XRPAmount fee,
+
2259 TxQ::Metrics&& escalationMetrics,
+
2260 LoadFeeTrack const& loadFeeTrack)
+
2261 : loadFactorServer{loadFeeTrack.getLoadFactor()}
+
2262 , loadBaseServer{loadFeeTrack.getLoadBase()}
+
2263 , baseFee{fee}
+
2264 , em{std::move(escalationMetrics)}
+
2265{
+
2266}
+
2267
+
2268bool
+
2269NetworkOPsImp::ServerFeeSummary::operator!=(
+
2270 NetworkOPsImp::ServerFeeSummary const& b) const
+
2271{
+
2272 if (loadFactorServer != b.loadFactorServer ||
+
2273 loadBaseServer != b.loadBaseServer || baseFee != b.baseFee ||
+
2274 em.has_value() != b.em.has_value())
+
2275 return true;
+
2276
+
2277 if (em && b.em)
+
2278 {
+
2279 return (
+
2280 em->minProcessingFeeLevel != b.em->minProcessingFeeLevel ||
+
2281 em->openLedgerFeeLevel != b.em->openLedgerFeeLevel ||
+
2282 em->referenceFeeLevel != b.em->referenceFeeLevel);
+
2283 }
+
2284
+
2285 return false;
+
2286}
+
2287
+
2288// Need to cap to uint64 to uint32 due to JSON limitations
+
2289static std::uint32_t
+
2290trunc32(std::uint64_t v)
+
2291{
+
2292 constexpr std::uint64_t max32 = std::numeric_limits<std::uint32_t>::max();
+
2293
+
2294 return std::min(max32, v);
+
2295};
+
2296
+
2297void
+
2298NetworkOPsImp::pubServer()
+
2299{
+
2300 // VFALCO TODO Don't hold the lock across calls to send...make a copy of the
+
2301 // list into a local array while holding the lock then release
+
2302 // the lock and call send on everyone.
+
2303 //
+
2304 std::lock_guard sl(mSubLock);
+
2305
+
2306 if (!mStreamMaps[sServer].empty())
+
2307 {
+
2308 Json::Value jvObj(Json::objectValue);
+
2309
+
2310 ServerFeeSummary f{
+
2311 app_.openLedger().current()->fees().base,
+
2312 app_.getTxQ().getMetrics(*app_.openLedger().current()),
+
2313 app_.getFeeTrack()};
+
2314
+
2315 jvObj[jss::type] = "serverStatus";
+
2316 jvObj[jss::server_status] = strOperatingMode();
+
2317 jvObj[jss::load_base] = f.loadBaseServer;
+
2318 jvObj[jss::load_factor_server] = f.loadFactorServer;
+
2319 jvObj[jss::base_fee] = f.baseFee.jsonClipped();
+
2320
+
2321 if (f.em)
+
2322 {
+
2323 auto const loadFactor = std::max(
+
2324 safe_cast<std::uint64_t>(f.loadFactorServer),
+
2325 mulDiv(
+
2326 f.em->openLedgerFeeLevel,
+
2327 f.loadBaseServer,
+
2328 f.em->referenceFeeLevel)
+
2329 .value_or(ripple::muldiv_max));
+
2330
+
2331 jvObj[jss::load_factor] = trunc32(loadFactor);
+
2332 jvObj[jss::load_factor_fee_escalation] =
+
2333 f.em->openLedgerFeeLevel.jsonClipped();
+
2334 jvObj[jss::load_factor_fee_queue] =
+
2335 f.em->minProcessingFeeLevel.jsonClipped();
+
2336 jvObj[jss::load_factor_fee_reference] =
+
2337 f.em->referenceFeeLevel.jsonClipped();
+
2338 }
+
2339 else
+
2340 jvObj[jss::load_factor] = f.loadFactorServer;
+
2341
+
2342 mLastFeeSummary = f;
+
2343
+
2344 for (auto i = mStreamMaps[sServer].begin();
+
2345 i != mStreamMaps[sServer].end();)
+
2346 {
+
2347 InfoSub::pointer p = i->second.lock();
+
2348
+
2349 // VFALCO TODO research the possibility of using thread queues and
+
2350 // linearizing the deletion of subscribers with the
+
2351 // sending of JSON data.
+
2352 if (p)
+
2353 {
+
2354 p->send(jvObj, true);
+
2355 ++i;
+
2356 }
+
2357 else
+
2358 {
+
2359 i = mStreamMaps[sServer].erase(i);
+
2360 }
+
2361 }
+
2362 }
+
2363}
+
2364
+
2365void
+
2366NetworkOPsImp::pubConsensus(ConsensusPhase phase)
+
2367{
+
2368 std::lock_guard sl(mSubLock);
+
2369
+
2370 auto& streamMap = mStreamMaps[sConsensusPhase];
+
2371 if (!streamMap.empty())
+
2372 {
+
2373 Json::Value jvObj(Json::objectValue);
+
2374 jvObj[jss::type] = "consensusPhase";
+
2375 jvObj[jss::consensus] = to_string(phase);
+
2376
+
2377 for (auto i = streamMap.begin(); i != streamMap.end();)
+
2378 {
+
2379 if (auto p = i->second.lock())
+
2380 {
+
2381 p->send(jvObj, true);
+
2382 ++i;
+
2383 }
+
2384 else
+
2385 {
+
2386 i = streamMap.erase(i);
+
2387 }
+
2388 }
+
2389 }
+
2390}
+
2391
+
2392void
+
2393NetworkOPsImp::pubValidation(std::shared_ptr<STValidation> const& val)
+
2394{
+
2395 // VFALCO consider std::shared_mutex
+
2396 std::lock_guard sl(mSubLock);
+
2397
+
2398 if (!mStreamMaps[sValidations].empty())
+
2399 {
+
2400 Json::Value jvObj(Json::objectValue);
+
2401
+
2402 auto const signerPublic = val->getSignerPublic();
+
2403
+
2404 jvObj[jss::type] = "validationReceived";
+
2405 jvObj[jss::validation_public_key] =
+
2406 toBase58(TokenType::NodePublic, signerPublic);
+
2407 jvObj[jss::ledger_hash] = to_string(val->getLedgerHash());
+
2408 jvObj[jss::signature] = strHex(val->getSignature());
+
2409 jvObj[jss::full] = val->isFull();
+
2410 jvObj[jss::flags] = val->getFlags();
+
2411 jvObj[jss::signing_time] = *(*val)[~sfSigningTime];
+
2412 jvObj[jss::data] = strHex(val->getSerializer().slice());
+
2413
+
2414 if (auto version = (*val)[~sfServerVersion])
+
2415 jvObj[jss::server_version] = std::to_string(*version);
+
2416
+
2417 if (auto cookie = (*val)[~sfCookie])
+
2418 jvObj[jss::cookie] = std::to_string(*cookie);
+
2419
+
2420 if (auto hash = (*val)[~sfValidatedHash])
+
2421 jvObj[jss::validated_hash] = strHex(*hash);
+
2422
+
2423 auto const masterKey =
+
2424 app_.validatorManifests().getMasterKey(signerPublic);
+
2425
+
2426 if (masterKey != signerPublic)
+
2427 jvObj[jss::master_key] = toBase58(TokenType::NodePublic, masterKey);
+
2428
+
2429 // NOTE *seq is a number, but old API versions used string. We replace
+
2430 // number with a string using MultiApiJson near end of this function
+
2431 if (auto const seq = (*val)[~sfLedgerSequence])
+
2432 jvObj[jss::ledger_index] = *seq;
+
2433
+
2434 if (val->isFieldPresent(sfAmendments))
+
2435 {
+
2436 jvObj[jss::amendments] = Json::Value(Json::arrayValue);
+
2437 for (auto const& amendment : val->getFieldV256(sfAmendments))
+
2438 jvObj[jss::amendments].append(to_string(amendment));
+
2439 }
+
2440
+
2441 if (auto const closeTime = (*val)[~sfCloseTime])
+
2442 jvObj[jss::close_time] = *closeTime;
+
2443
+
2444 if (auto const loadFee = (*val)[~sfLoadFee])
+
2445 jvObj[jss::load_fee] = *loadFee;
+
2446
+
2447 if (auto const baseFee = val->at(~sfBaseFee))
+
2448 jvObj[jss::base_fee] = static_cast<double>(*baseFee);
+
2449
+
2450 if (auto const reserveBase = val->at(~sfReserveBase))
+
2451 jvObj[jss::reserve_base] = *reserveBase;
+
2452
+
2453 if (auto const reserveInc = val->at(~sfReserveIncrement))
+
2454 jvObj[jss::reserve_inc] = *reserveInc;
+
2455
+
2456 // (The ~ operator converts the Proxy to a std::optional, which
+
2457 // simplifies later operations)
+
2458 if (auto const baseFeeXRP = ~val->at(~sfBaseFeeDrops);
+
2459 baseFeeXRP && baseFeeXRP->native())
+
2460 jvObj[jss::base_fee] = baseFeeXRP->xrp().jsonClipped();
+
2461
+
2462 if (auto const reserveBaseXRP = ~val->at(~sfReserveBaseDrops);
+
2463 reserveBaseXRP && reserveBaseXRP->native())
+
2464 jvObj[jss::reserve_base] = reserveBaseXRP->xrp().jsonClipped();
+
2465
+
2466 if (auto const reserveIncXRP = ~val->at(~sfReserveIncrementDrops);
+
2467 reserveIncXRP && reserveIncXRP->native())
+
2468 jvObj[jss::reserve_inc] = reserveIncXRP->xrp().jsonClipped();
+
2469
+
2470 // NOTE Use MultiApiJson to publish two slightly different JSON objects
+
2471 // for consumers supporting different API versions
+
2472 MultiApiJson multiObj{jvObj};
+
2473 multiObj.visit(
+
2474 RPC::apiVersion<1>, //
+
2475 [](Json::Value& jvTx) {
+
2476 // Type conversion for older API versions to string
+
2477 if (jvTx.isMember(jss::ledger_index))
+
2478 {
+
2479 jvTx[jss::ledger_index] =
+
2480 std::to_string(jvTx[jss::ledger_index].asUInt());
+
2481 }
+
2482 });
+
2483
+
2484 for (auto i = mStreamMaps[sValidations].begin();
+
2485 i != mStreamMaps[sValidations].end();)
+
2486 {
+
2487 if (auto p = i->second.lock())
+
2488 {
+
2489 multiObj.visit(
+
2490 p->getApiVersion(), //
+
2491 [&](Json::Value const& jv) { p->send(jv, true); });
+
2492 ++i;
+
2493 }
+
2494 else
+
2495 {
+
2496 i = mStreamMaps[sValidations].erase(i);
+
2497 }
+
2498 }
+
2499 }
+
2500}
+
2501
+
2502void
+
2503NetworkOPsImp::pubPeerStatus(std::function<Json::Value(void)> const& func)
+
2504{
+
2505 std::lock_guard sl(mSubLock);
+
2506
+
2507 if (!mStreamMaps[sPeerStatus].empty())
+
2508 {
+
2509 Json::Value jvObj(func());
+
2510
+
2511 jvObj[jss::type] = "peerStatusChange";
+
2512
+
2513 for (auto i = mStreamMaps[sPeerStatus].begin();
+
2514 i != mStreamMaps[sPeerStatus].end();)
+
2515 {
+
2516 InfoSub::pointer p = i->second.lock();
+
2517
+
2518 if (p)
+
2519 {
+
2520 p->send(jvObj, true);
+
2521 ++i;
+
2522 }
+
2523 else
+
2524 {
+
2525 i = mStreamMaps[sPeerStatus].erase(i);
+
2526 }
+
2527 }
+
2528 }
+
2529}
+
2530
+
2531void
+
2532NetworkOPsImp::setMode(OperatingMode om)
+
2533{
+
2534 using namespace std::chrono_literals;
+
2535 if (om == OperatingMode::CONNECTED)
+
2536 {
+
2537 if (app_.getLedgerMaster().getValidatedLedgerAge() < 1min)
+
2538 om = OperatingMode::SYNCING;
+
2539 }
+
2540 else if (om == OperatingMode::SYNCING)
+
2541 {
+
2542 if (app_.getLedgerMaster().getValidatedLedgerAge() >= 1min)
+
2543 om = OperatingMode::CONNECTED;
+
2544 }
+
2545
+
2546 if ((om > OperatingMode::CONNECTED) && isBlocked())
+
2547 om = OperatingMode::CONNECTED;
+
2548
+
2549 if (mMode == om)
+
2550 return;
+
2551
+
2552 mMode = om;
+
2553
+
2554 accounting_.mode(om);
+
2555
+
2556 JLOG(m_journal.info()) << "STATE->" << strOperatingMode();
+
2557 pubServer();
+
2558}
+
2559
+
2560bool
+
2561NetworkOPsImp::recvValidation(
+
2562 std::shared_ptr<STValidation> const& val,
+
2563 std::string const& source)
+
2564{
+
2565 JLOG(m_journal.trace())
+
2566 << "recvValidation " << val->getLedgerHash() << " from " << source;
+
2567
+
2568 std::unique_lock lock(validationsMutex_);
+
2569 BypassAccept bypassAccept = BypassAccept::no;
+
2570 try
+
2571 {
+
2572 if (pendingValidations_.contains(val->getLedgerHash()))
+
2573 bypassAccept = BypassAccept::yes;
+
2574 else
+
2575 pendingValidations_.insert(val->getLedgerHash());
+
2576 scope_unlock unlock(lock);
+
2577 handleNewValidation(app_, val, source, bypassAccept, m_journal);
+
2578 }
+
2579 catch (std::exception const& e)
+
2580 {
+
2581 JLOG(m_journal.warn())
+
2582 << "Exception thrown for handling new validation "
+
2583 << val->getLedgerHash() << ": " << e.what();
+
2584 }
+
2585 catch (...)
+
2586 {
+
2587 JLOG(m_journal.warn())
+
2588 << "Unknown exception thrown for handling new validation "
+
2589 << val->getLedgerHash();
+
2590 }
+
2591 if (bypassAccept == BypassAccept::no)
+
2592 {
+
2593 pendingValidations_.erase(val->getLedgerHash());
+
2594 }
+
2595 lock.unlock();
+
2596
+
2597 pubValidation(val);
+
2598
+
2599 JLOG(m_journal.debug()) << [this, &val]() -> auto {
+
2600 std::stringstream ss;
+
2601 ss << "VALIDATION: " << val->render() << " master_key: ";
+
2602 auto master = app_.validators().getTrustedKey(val->getSignerPublic());
+
2603 if (master)
+
2604 {
+
2605 ss << toBase58(TokenType::NodePublic, *master);
+
2606 }
+
2607 else
+
2608 {
+
2609 ss << "none";
+
2610 }
+
2611 return ss.str();
+
2612 }();
+
2613
+
2614 // We will always relay trusted validations; if configured, we will
+
2615 // also relay all untrusted validations.
+
2616 return app_.config().RELAY_UNTRUSTED_VALIDATIONS == 1 || val->isTrusted();
+
2617}
+
2618
+
2619Json::Value
+
2620NetworkOPsImp::getConsensusInfo()
+
2621{
+
2622 return mConsensus.getJson(true);
+
2623}
+
2624
+
2625Json::Value
+
2626NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters)
+
2627{
+
2628 Json::Value info = Json::objectValue;
+
2629
+
2630 // System-level warnings
+
2631 {
+
2632 Json::Value warnings{Json::arrayValue};
+
2633 if (isAmendmentBlocked())
+
2634 {
+
2635 Json::Value& w = warnings.append(Json::objectValue);
+
2636 w[jss::id] = warnRPC_AMENDMENT_BLOCKED;
+
2637 w[jss::message] =
+
2638 "This server is amendment blocked, and must be updated to be "
+
2639 "able to stay in sync with the network.";
+
2640 }
+
2641 if (isUNLBlocked())
+
2642 {
+
2643 Json::Value& w = warnings.append(Json::objectValue);
+
2644 w[jss::id] = warnRPC_EXPIRED_VALIDATOR_LIST;
+
2645 w[jss::message] =
+
2646 "This server has an expired validator list. validators.txt "
+
2647 "may be incorrectly configured or some [validator_list_sites] "
+
2648 "may be unreachable.";
+
2649 }
+
2650 if (admin && isAmendmentWarned())
+
2651 {
+
2652 Json::Value& w = warnings.append(Json::objectValue);
+
2653 w[jss::id] = warnRPC_UNSUPPORTED_MAJORITY;
+
2654 w[jss::message] =
+
2655 "One or more unsupported amendments have reached majority. "
+
2656 "Upgrade to the latest version before they are activated "
+
2657 "to avoid being amendment blocked.";
+
2658 if (auto const expected =
+
2659 app_.getAmendmentTable().firstUnsupportedExpected())
+
2660 {
+
2661 auto& d = w[jss::details] = Json::objectValue;
+
2662 d[jss::expected_date] = expected->time_since_epoch().count();
+
2663 d[jss::expected_date_UTC] = to_string(*expected);
+
2664 }
+
2665 }
+
2666
+
2667 if (warnings.size())
+
2668 info[jss::warnings] = std::move(warnings);
+
2669 }
+
2670
+
2671 // hostid: unique string describing the machine
+
2672 if (human)
+
2673 info[jss::hostid] = getHostId(admin);
+
2674
+
2675 // domain: if configured with a domain, report it:
+
2676 if (!app_.config().SERVER_DOMAIN.empty())
+
2677 info[jss::server_domain] = app_.config().SERVER_DOMAIN;
+
2678
+
2679 info[jss::build_version] = BuildInfo::getVersionString();
+
2680
+
2681 info[jss::server_state] = strOperatingMode(admin);
+
2682
+
2683 info[jss::time] = to_string(std::chrono::floor<std::chrono::microseconds>(
+
2684 std::chrono::system_clock::now()));
+
2685
+
2686 if (needNetworkLedger_)
+
2687 info[jss::network_ledger] = "waiting";
+
2688
+
2689 info[jss::validation_quorum] =
+
2690 static_cast<Json::UInt>(app_.validators().quorum());
+
2691
+
2692 if (admin)
+
2693 {
+
2694 switch (app_.config().NODE_SIZE)
+
2695 {
+
2696 case 0:
+
2697 info[jss::node_size] = "tiny";
+
2698 break;
+
2699 case 1:
+
2700 info[jss::node_size] = "small";
+
2701 break;
+
2702 case 2:
+
2703 info[jss::node_size] = "medium";
+
2704 break;
+
2705 case 3:
+
2706 info[jss::node_size] = "large";
+
2707 break;
+
2708 case 4:
+
2709 info[jss::node_size] = "huge";
+
2710 break;
+
2711 }
+
2712
+
2713 auto when = app_.validators().expires();
+
2714
+
2715 if (!human)
+
2716 {
+
2717 if (when)
+
2718 info[jss::validator_list_expires] =
+
2719 safe_cast<Json::UInt>(when->time_since_epoch().count());
+
2720 else
+
2721 info[jss::validator_list_expires] = 0;
+
2722 }
+
2723 else
+
2724 {
+
2725 auto& x = (info[jss::validator_list] = Json::objectValue);
+
2726
+
2727 x[jss::count] = static_cast<Json::UInt>(app_.validators().count());
+
2728
+
2729 if (when)
+
2730 {
+
2731 if (*when == TimeKeeper::time_point::max())
+
2732 {
+
2733 x[jss::expiration] = "never";
+
2734 x[jss::status] = "active";
+
2735 }
+
2736 else
+
2737 {
+
2738 x[jss::expiration] = to_string(*when);
+
2739
+
2740 if (*when > app_.timeKeeper().now())
+
2741 x[jss::status] = "active";
+
2742 else
+
2743 x[jss::status] = "expired";
+
2744 }
+
2745 }
+
2746 else
+
2747 {
+
2748 x[jss::status] = "unknown";
+
2749 x[jss::expiration] = "unknown";
+
2750 }
+
2751 }
+
2752
+
2753#if defined(GIT_COMMIT_HASH) || defined(GIT_BRANCH)
+
2754 {
+
2755 auto& x = (info[jss::git] = Json::objectValue);
+
2756#ifdef GIT_COMMIT_HASH
+
2757 x[jss::hash] = GIT_COMMIT_HASH;
+
2758#endif
+
2759#ifdef GIT_BRANCH
+
2760 x[jss::branch] = GIT_BRANCH;
+
2761#endif
+
2762 }
+
2763#endif
+
2764 }
+
2765 info[jss::io_latency_ms] =
+
2766 static_cast<Json::UInt>(app_.getIOLatency().count());
+
2767
+
2768 if (admin)
+
2769 {
+
2770 if (auto const localPubKey = app_.validators().localPublicKey();
+
2771 localPubKey && app_.getValidationPublicKey())
+
2772 {
+
2773 info[jss::pubkey_validator] =
+
2774 toBase58(TokenType::NodePublic, localPubKey.value());
+
2775 }
+
2776 else
+
2777 {
+
2778 info[jss::pubkey_validator] = "none";
+
2779 }
+
2780 }
+
2781
+
2782 if (counters)
+
2783 {
+
2784 info[jss::counters] = app_.getPerfLog().countersJson();
+
2785
+
2786 Json::Value nodestore(Json::objectValue);
+
2787 app_.getNodeStore().getCountsJson(nodestore);
+
2788 info[jss::counters][jss::nodestore] = nodestore;
+
2789 info[jss::current_activities] = app_.getPerfLog().currentJson();
+
2790 }
+
2791
+
2792 info[jss::pubkey_node] =
+
2793 toBase58(TokenType::NodePublic, app_.nodeIdentity().first);
+
2794
+
2795 info[jss::complete_ledgers] = app_.getLedgerMaster().getCompleteLedgers();
+
2796
+
2797 if (amendmentBlocked_)
+
2798 info[jss::amendment_blocked] = true;
+
2799
+
2800 auto const fp = m_ledgerMaster.getFetchPackCacheSize();
+
2801
+
2802 if (fp != 0)
+
2803 info[jss::fetch_pack] = Json::UInt(fp);
+
2804
+
2805 info[jss::peers] = Json::UInt(app_.overlay().size());
+
2806
+
2807 Json::Value lastClose = Json::objectValue;
+
2808 lastClose[jss::proposers] = Json::UInt(mConsensus.prevProposers());
+
2809
+
2810 if (human)
+
2811 {
+
2812 lastClose[jss::converge_time_s] =
+
2813 std::chrono::duration<double>{mConsensus.prevRoundTime()}.count();
+
2814 }
+
2815 else
+
2816 {
+
2817 lastClose[jss::converge_time] =
+
2818 Json::Int(mConsensus.prevRoundTime().count());
+
2819 }
+
2820
+
2821 info[jss::last_close] = lastClose;
+
2822
+
2823 // info[jss::consensus] = mConsensus.getJson();
+
2824
+
2825 if (admin)
+
2826 info[jss::load] = m_job_queue.getJson();
+
2827
+
2828 if (auto const netid = app_.overlay().networkID())
+
2829 info[jss::network_id] = static_cast<Json::UInt>(*netid);
+
2830
+
2831 auto const escalationMetrics =
+
2832 app_.getTxQ().getMetrics(*app_.openLedger().current());
+
2833
+
2834 auto const loadFactorServer = app_.getFeeTrack().getLoadFactor();
+
2835 auto const loadBaseServer = app_.getFeeTrack().getLoadBase();
+
2836 /* Scale the escalated fee level to unitless "load factor".
+
2837 In practice, this just strips the units, but it will continue
+
2838 to work correctly if either base value ever changes. */
+
2839 auto const loadFactorFeeEscalation =
+
2840 mulDiv(
+
2841 escalationMetrics.openLedgerFeeLevel,
+
2842 loadBaseServer,
+
2843 escalationMetrics.referenceFeeLevel)
+
2844 .value_or(ripple::muldiv_max);
+
2845
+
2846 auto const loadFactor = std::max(
+
2847 safe_cast<std::uint64_t>(loadFactorServer), loadFactorFeeEscalation);
+
2848
+
2849 if (!human)
+
2850 {
+
2851 info[jss::load_base] = loadBaseServer;
+
2852 info[jss::load_factor] = trunc32(loadFactor);
+
2853 info[jss::load_factor_server] = loadFactorServer;
+
2854
+
2855 /* Json::Value doesn't support uint64, so clamp to max
+
2856 uint32 value. This is mostly theoretical, since there
+
2857 probably isn't enough extant XRP to drive the factor
+
2858 that high.
+
2859 */
+
2860 info[jss::load_factor_fee_escalation] =
+
2861 escalationMetrics.openLedgerFeeLevel.jsonClipped();
+
2862 info[jss::load_factor_fee_queue] =
+
2863 escalationMetrics.minProcessingFeeLevel.jsonClipped();
+
2864 info[jss::load_factor_fee_reference] =
+
2865 escalationMetrics.referenceFeeLevel.jsonClipped();
+
2866 }
+
2867 else
+
2868 {
+
2869 info[jss::load_factor] =
+
2870 static_cast<double>(loadFactor) / loadBaseServer;
+
2871
+
2872 if (loadFactorServer != loadFactor)
+
2873 info[jss::load_factor_server] =
+
2874 static_cast<double>(loadFactorServer) / loadBaseServer;
+
2875
+
2876 if (admin)
+
2877 {
+
2878 std::uint32_t fee = app_.getFeeTrack().getLocalFee();
+
2879 if (fee != loadBaseServer)
+
2880 info[jss::load_factor_local] =
+
2881 static_cast<double>(fee) / loadBaseServer;
+
2882 fee = app_.getFeeTrack().getRemoteFee();
+
2883 if (fee != loadBaseServer)
+
2884 info[jss::load_factor_net] =
+
2885 static_cast<double>(fee) / loadBaseServer;
+
2886 fee = app_.getFeeTrack().getClusterFee();
+
2887 if (fee != loadBaseServer)
+
2888 info[jss::load_factor_cluster] =
+
2889 static_cast<double>(fee) / loadBaseServer;
+
2890 }
+
2891 if (escalationMetrics.openLedgerFeeLevel !=
+
2892 escalationMetrics.referenceFeeLevel &&
+
2893 (admin || loadFactorFeeEscalation != loadFactor))
+
2894 info[jss::load_factor_fee_escalation] =
+
2895 escalationMetrics.openLedgerFeeLevel.decimalFromReference(
+
2896 escalationMetrics.referenceFeeLevel);
+
2897 if (escalationMetrics.minProcessingFeeLevel !=
+
2898 escalationMetrics.referenceFeeLevel)
+
2899 info[jss::load_factor_fee_queue] =
+
2900 escalationMetrics.minProcessingFeeLevel.decimalFromReference(
+
2901 escalationMetrics.referenceFeeLevel);
+
2902 }
+
2903
+
2904 bool valid = false;
+
2905 auto lpClosed = m_ledgerMaster.getValidatedLedger();
+
2906
+
2907 if (lpClosed)
+
2908 valid = true;
+
2909 else
+
2910 lpClosed = m_ledgerMaster.getClosedLedger();
+
2911
+
2912 if (lpClosed)
+
2913 {
+
2914 XRPAmount const baseFee = lpClosed->fees().base;
+
2915 Json::Value l(Json::objectValue);
+
2916 l[jss::seq] = Json::UInt(lpClosed->info().seq);
+
2917 l[jss::hash] = to_string(lpClosed->info().hash);
+
2918
+
2919 if (!human)
+
2920 {
+
2921 l[jss::base_fee] = baseFee.jsonClipped();
+
2922 l[jss::reserve_base] =
+
2923 lpClosed->fees().accountReserve(0).jsonClipped();
+
2924 l[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
+
2925 l[jss::close_time] = Json::Value::UInt(
+
2926 lpClosed->info().closeTime.time_since_epoch().count());
+
2927 }
+
2928 else
+
2929 {
+
2930 l[jss::base_fee_xrp] = baseFee.decimalXRP();
+
2931 l[jss::reserve_base_xrp] =
+
2932 lpClosed->fees().accountReserve(0).decimalXRP();
+
2933 l[jss::reserve_inc_xrp] = lpClosed->fees().increment.decimalXRP();
+
2934
+
2935 if (auto const closeOffset = app_.timeKeeper().closeOffset();
+
2936 std::abs(closeOffset.count()) >= 60)
+
2937 l[jss::close_time_offset] =
+
2938 static_cast<std::uint32_t>(closeOffset.count());
+
2939
+
2940 constexpr std::chrono::seconds highAgeThreshold{1000000};
+
2941 if (m_ledgerMaster.haveValidated())
+
2942 {
+
2943 auto const age = m_ledgerMaster.getValidatedLedgerAge();
+
2944 l[jss::age] =
+
2945 Json::UInt(age < highAgeThreshold ? age.count() : 0);
+
2946 }
+
2947 else
+
2948 {
+
2949 auto lCloseTime = lpClosed->info().closeTime;
+
2950 auto closeTime = app_.timeKeeper().closeTime();
+
2951 if (lCloseTime <= closeTime)
+
2952 {
+
2953 using namespace std::chrono_literals;
+
2954 auto age = closeTime - lCloseTime;
+
2955 l[jss::age] =
+
2956 Json::UInt(age < highAgeThreshold ? age.count() : 0);
+
2957 }
+
2958 }
+
2959 }
+
2960
+
2961 if (valid)
+
2962 info[jss::validated_ledger] = l;
+
2963 else
+
2964 info[jss::closed_ledger] = l;
+
2965
+
2966 auto lpPublished = m_ledgerMaster.getPublishedLedger();
+
2967 if (!lpPublished)
+
2968 info[jss::published_ledger] = "none";
+
2969 else if (lpPublished->info().seq != lpClosed->info().seq)
+
2970 info[jss::published_ledger] = lpPublished->info().seq;
+
2971 }
+
2972
+
2973 accounting_.json(info);
+
2974 info[jss::uptime] = UptimeClock::now().time_since_epoch().count();
+
2975 info[jss::jq_trans_overflow] =
+
2976 std::to_string(app_.overlay().getJqTransOverflow());
+
2977 info[jss::peer_disconnects] =
+
2978 std::to_string(app_.overlay().getPeerDisconnect());
+
2979 info[jss::peer_disconnects_resources] =
+
2980 std::to_string(app_.overlay().getPeerDisconnectCharges());
+
2981
+
2982 // This array must be sorted in increasing order.
+
2983 static constexpr std::array<std::string_view, 7> protocols{
+
2984 "http", "https", "peer", "ws", "ws2", "wss", "wss2"};
+
2985 static_assert(std::is_sorted(std::begin(protocols), std::end(protocols)));
+
2986 {
+
2987 Json::Value ports{Json::arrayValue};
+
2988 for (auto const& port : app_.getServerHandler().setup().ports)
+
2989 {
+
2990 // Don't publish admin ports for non-admin users
+
2991 if (!admin &&
+
2992 !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty() &&
+
2993 port.admin_user.empty() && port.admin_password.empty()))
+
2994 continue;
+
2995 std::vector<std::string> proto;
+
2996 std::set_intersection(
+
2997 std::begin(port.protocol),
+
2998 std::end(port.protocol),
+
2999 std::begin(protocols),
+
3000 std::end(protocols),
+
3001 std::back_inserter(proto));
+
3002 if (!proto.empty())
+
3003 {
+
3004 auto& jv = ports.append(Json::Value(Json::objectValue));
+
3005 jv[jss::port] = std::to_string(port.port);
+
3006 jv[jss::protocol] = Json::Value{Json::arrayValue};
+
3007 for (auto const& p : proto)
+
3008 jv[jss::protocol].append(p);
+
3009 }
+
3010 }
+
3011
+
3012 if (app_.config().exists(SECTION_PORT_GRPC))
+
3013 {
+
3014 auto const& grpcSection = app_.config().section(SECTION_PORT_GRPC);
+
3015 auto const optPort = grpcSection.get("port");
+
3016 if (optPort && grpcSection.get("ip"))
+
3017 {
+
3018 auto& jv = ports.append(Json::Value(Json::objectValue));
+
3019 jv[jss::port] = *optPort;
+
3020 jv[jss::protocol] = Json::Value{Json::arrayValue};
+
3021 jv[jss::protocol].append("grpc");
+
3022 }
+
3023 }
+
3024 info[jss::ports] = std::move(ports);
+
3025 }
+
3026
+
3027 return info;
+
3028}
+
3029
+
3030void
+
3031NetworkOPsImp::clearLedgerFetch()
+
3032{
+
3033 app_.getInboundLedgers().clearFailures();
+
3034}
+
3035
+
3036Json::Value
+
3037NetworkOPsImp::getLedgerFetchInfo()
+
3038{
+
3039 return app_.getInboundLedgers().getInfo();
+
3040}
+
3041
+
3042void
+
3043NetworkOPsImp::pubProposedTransaction(
+
3044 std::shared_ptr<ReadView const> const& ledger,
+
3045 std::shared_ptr<STTx const> const& transaction,
+
3046 TER result)
+
3047{
+
3048 // never publish an inner txn inside a batch txn
+
3049 if (transaction->isFlag(tfInnerBatchTxn) &&
+
3050 ledger->rules().enabled(featureBatch))
+
3051 return;
+
3052
+
3053 MultiApiJson jvObj =
+
3054 transJson(transaction, result, false, ledger, std::nullopt);
+
3055
+
3056 {
+
3057 std::lock_guard sl(mSubLock);
+
3058
+
3059 auto it = mStreamMaps[sRTTransactions].begin();
+
3060 while (it != mStreamMaps[sRTTransactions].end())
+
3061 {
+
3062 InfoSub::pointer p = it->second.lock();
+
3063
+
3064 if (p)
+
3065 {
+
3066 jvObj.visit(
+
3067 p->getApiVersion(), //
+
3068 [&](Json::Value const& jv) { p->send(jv, true); });
+
3069 ++it;
+
3070 }
+
3071 else
+
3072 {
+
3073 it = mStreamMaps[sRTTransactions].erase(it);
+
3074 }
+
3075 }
+
3076 }
+
3077
+
3078 pubProposedAccountTransaction(ledger, transaction, result);
+
3079}
+
3080
+
3081void
+
3082NetworkOPsImp::pubLedger(std::shared_ptr<ReadView const> const& lpAccepted)
+
3083{
+
3084 // Ledgers are published only when they acquire sufficient validations
+
3085 // Holes are filled across connection loss or other catastrophe
+
3086
+
3087 std::shared_ptr<AcceptedLedger> alpAccepted =
+
3088 app_.getAcceptedLedgerCache().fetch(lpAccepted->info().hash);
+
3089 if (!alpAccepted)
+
3090 {
+
3091 alpAccepted = std::make_shared<AcceptedLedger>(lpAccepted, app_);
+
3092 app_.getAcceptedLedgerCache().canonicalize_replace_client(
+
3093 lpAccepted->info().hash, alpAccepted);
+
3094 }
+
3095
+
3096 XRPL_ASSERT(
+
3097 alpAccepted->getLedger().get() == lpAccepted.get(),
+
3098 "ripple::NetworkOPsImp::pubLedger : accepted input");
+
3099
+
3100 {
+
3101 JLOG(m_journal.debug())
+
3102 << "Publishing ledger " << lpAccepted->info().seq << " "
+
3103 << lpAccepted->info().hash;
+
3104
+
3105 std::lock_guard sl(mSubLock);
+
3106
+
3107 if (!mStreamMaps[sLedger].empty())
+
3108 {
+
3109 Json::Value jvObj(Json::objectValue);
+
3110
+
3111 jvObj[jss::type] = "ledgerClosed";
+
3112 jvObj[jss::ledger_index] = lpAccepted->info().seq;
+
3113 jvObj[jss::ledger_hash] = to_string(lpAccepted->info().hash);
+
3114 jvObj[jss::ledger_time] = Json::Value::UInt(
+
3115 lpAccepted->info().closeTime.time_since_epoch().count());
+
3116
+
3117 if (!lpAccepted->rules().enabled(featureXRPFees))
+
3118 jvObj[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED;
+
3119 jvObj[jss::fee_base] = lpAccepted->fees().base.jsonClipped();
+
3120 jvObj[jss::reserve_base] =
+
3121 lpAccepted->fees().accountReserve(0).jsonClipped();
+
3122 jvObj[jss::reserve_inc] =
+
3123 lpAccepted->fees().increment.jsonClipped();
+
3124
+
3125 jvObj[jss::txn_count] = Json::UInt(alpAccepted->size());
+
3126
+
3127 if (mMode >= OperatingMode::SYNCING)
+
3128 {
+
3129 jvObj[jss::validated_ledgers] =
+
3130 app_.getLedgerMaster().getCompleteLedgers();
+
3131 }
+
3132
+
3133 auto it = mStreamMaps[sLedger].begin();
+
3134 while (it != mStreamMaps[sLedger].end())
+
3135 {
+
3136 InfoSub::pointer p = it->second.lock();
+
3137 if (p)
+
3138 {
+
3139 p->send(jvObj, true);
+
3140 ++it;
+
3141 }
+
3142 else
+
3143 it = mStreamMaps[sLedger].erase(it);
+
3144 }
+
3145 }
+
3146
+
3147 if (!mStreamMaps[sBookChanges].empty())
+
3148 {
+
3149 Json::Value jvObj = ripple::RPC::computeBookChanges(lpAccepted);
+
3150
+
3151 auto it = mStreamMaps[sBookChanges].begin();
+
3152 while (it != mStreamMaps[sBookChanges].end())
+
3153 {
+
3154 InfoSub::pointer p = it->second.lock();
+
3155 if (p)
+
3156 {
+
3157 p->send(jvObj, true);
+
3158 ++it;
+
3159 }
+
3160 else
+
3161 it = mStreamMaps[sBookChanges].erase(it);
+
3162 }
+
3163 }
+
3164
+
3165 {
+
3166 static bool firstTime = true;
+
3167 if (firstTime)
+
3168 {
+
3169 // First validated ledger, start delayed SubAccountHistory
+
3170 firstTime = false;
+
3171 for (auto& outer : mSubAccountHistory)
+
3172 {
+
3173 for (auto& inner : outer.second)
+
3174 {
+
3175 auto& subInfo = inner.second;
+
3176 if (subInfo.index_->separationLedgerSeq_ == 0)
+
3177 {
+
3178 subAccountHistoryStart(
+
3179 alpAccepted->getLedger(), subInfo);
+
3180 }
+
3181 }
+
3182 }
+
3183 }
+
3184 }
+
3185 }
+
3186
+
3187 // Don't lock since pubAcceptedTransaction is locking.
+
3188 for (auto const& accTx : *alpAccepted)
+
3189 {
+
3190 JLOG(m_journal.trace()) << "pubAccepted: " << accTx->getJson();
+
3191 pubValidatedTransaction(
+
3192 lpAccepted, *accTx, accTx == *(--alpAccepted->end()));
+
3193 }
+
3194}
+
3195
+
3196void
+
3197NetworkOPsImp::reportFeeChange()
+
3198{
+
3199 ServerFeeSummary f{
+
3200 app_.openLedger().current()->fees().base,
+
3201 app_.getTxQ().getMetrics(*app_.openLedger().current()),
+
3202 app_.getFeeTrack()};
+
3203
+
3204 // only schedule the job if something has changed
+
3205 if (f != mLastFeeSummary)
+
3206 {
+
3207 m_job_queue.addJob(
+
3208 jtCLIENT_FEE_CHANGE, "reportFeeChange->pubServer", [this]() {
+
3209 pubServer();
+
3210 });
+
3211 }
+
3212}
+
3213
+
3214void
+
3215NetworkOPsImp::reportConsensusStateChange(ConsensusPhase phase)
+
3216{
+
3217 m_job_queue.addJob(
+
3218 jtCLIENT_CONSENSUS,
+
3219 "reportConsensusStateChange->pubConsensus",
+
3220 [this, phase]() { pubConsensus(phase); });
+
3221}
+
3222
+
3223inline void
+
3224NetworkOPsImp::updateLocalTx(ReadView const& view)
+
3225{
+
3226 m_localTX->sweep(view);
+
3227}
+
3228inline std::size_t
+
3229NetworkOPsImp::getLocalTxCount()
+
3230{
+
3231 return m_localTX->size();
+
3232}
+
3233
+
3234// This routine should only be used to publish accepted or validated
+
3235// transactions.
+
3236MultiApiJson
+
3237NetworkOPsImp::transJson(
+
3238 std::shared_ptr<STTx const> const& transaction,
+
3239 TER result,
+
3240 bool validated,
+
3241 std::shared_ptr<ReadView const> const& ledger,
+
3242 std::optional<std::reference_wrapper<TxMeta const>> meta)
+
3243{
+
3244 Json::Value jvObj(Json::objectValue);
+
3245 std::string sToken;
+
3246 std::string sHuman;
+
3247
+
3248 transResultInfo(result, sToken, sHuman);
+
3249
+
3250 jvObj[jss::type] = "transaction";
+
3251 // NOTE jvObj is not a finished object for either API version. After
+
3252 // it's populated, we need to finish it for a specific API version. This is
+
3253 // done in a loop, near the end of this function.
+
3254 jvObj[jss::transaction] =
+
3255 transaction->getJson(JsonOptions::disable_API_prior_V2, false);
+
3256
+
3257 if (meta)
+
3258 {
+
3259 jvObj[jss::meta] = meta->get().getJson(JsonOptions::none);
+
3260 RPC::insertDeliveredAmount(
+
3261 jvObj[jss::meta], *ledger, transaction, meta->get());
+
3262 RPC::insertNFTSyntheticInJson(jvObj, transaction, meta->get());
+
3263 RPC::insertMPTokenIssuanceID(
+
3264 jvObj[jss::meta], transaction, meta->get());
+
3265 }
+
3266
+
3267 // add CTID where the needed data for it exists
+
3268 if (auto const& lookup = ledger->txRead(transaction->getTransactionID());
+
3269 lookup.second && lookup.second->isFieldPresent(sfTransactionIndex))
+
3270 {
+
3271 uint32_t const txnSeq = lookup.second->getFieldU32(sfTransactionIndex);
+
3272 uint32_t netID = app_.config().NETWORK_ID;
+
3273 if (transaction->isFieldPresent(sfNetworkID))
+
3274 netID = transaction->getFieldU32(sfNetworkID);
+
3275
+
3276 if (std::optional<std::string> ctid =
+
3277 RPC::encodeCTID(ledger->info().seq, txnSeq, netID);
+
3278 ctid)
+
3279 jvObj[jss::ctid] = *ctid;
+
3280 }
+
3281 if (!ledger->open())
+
3282 jvObj[jss::ledger_hash] = to_string(ledger->info().hash);
+
3283
+
3284 if (validated)
+
3285 {
+
3286 jvObj[jss::ledger_index] = ledger->info().seq;
+
3287 jvObj[jss::transaction][jss::date] =
+
3288 ledger->info().closeTime.time_since_epoch().count();
+
3289 jvObj[jss::validated] = true;
+
3290 jvObj[jss::close_time_iso] = to_string_iso(ledger->info().closeTime);
+
3291
+
3292 // WRITEME: Put the account next seq here
+
3293 }
+
3294 else
+
3295 {
+
3296 jvObj[jss::validated] = false;
+
3297 jvObj[jss::ledger_current_index] = ledger->info().seq;
+
3298 }
+
3299
+
3300 jvObj[jss::status] = validated ? "closed" : "proposed";
+
3301 jvObj[jss::engine_result] = sToken;
+
3302 jvObj[jss::engine_result_code] = result;
+
3303 jvObj[jss::engine_result_message] = sHuman;
+
3304
+
3305 if (transaction->getTxnType() == ttOFFER_CREATE)
+
3306 {
+
3307 auto const account = transaction->getAccountID(sfAccount);
+
3308 auto const amount = transaction->getFieldAmount(sfTakerGets);
+
3309
+
3310 // If the offer create is not self funded then add the owner balance
+
3311 if (account != amount.issue().account)
+
3312 {
+
3313 auto const ownerFunds = accountFunds(
+
3314 *ledger,
+
3315 account,
+
3316 amount,
+
3317 fhIGNORE_FREEZE,
+
3318 app_.journal("View"));
+
3319 jvObj[jss::transaction][jss::owner_funds] = ownerFunds.getText();
+
3320 }
+
3321 }
+
3322
+
3323 std::string const hash = to_string(transaction->getTransactionID());
+
3324 MultiApiJson multiObj{jvObj};
+
3325 forAllApiVersions(
+
3326 multiObj.visit(), //
+
3327 [&]<unsigned Version>(
+
3328 Json::Value& jvTx, std::integral_constant<unsigned, Version>) {
+
3329 RPC::insertDeliverMax(
+
3330 jvTx[jss::transaction], transaction->getTxnType(), Version);
+
3331
+
3332 if constexpr (Version > 1)
+
3333 {
+
3334 jvTx[jss::tx_json] = jvTx.removeMember(jss::transaction);
+
3335 jvTx[jss::hash] = hash;
+
3336 }
+
3337 else
+
3338 {
+
3339 jvTx[jss::transaction][jss::hash] = hash;
+
3340 }
+
3341 });
+
3342
+
3343 return multiObj;
+
3344}
+
3345
+
3346void
+
3347NetworkOPsImp::pubValidatedTransaction(
+
3348 std::shared_ptr<ReadView const> const& ledger,
+
3349 AcceptedLedgerTx const& transaction,
+
3350 bool last)
+
3351{
+
3352 auto const& stTxn = transaction.getTxn();
+
3353
+
3354 // Create two different Json objects, for different API versions
+
3355 auto const metaRef = std::ref(transaction.getMeta());
+
3356 auto const trResult = transaction.getResult();
+
3357 MultiApiJson jvObj = transJson(stTxn, trResult, true, ledger, metaRef);
+
3358
+
3359 {
+
3360 std::lock_guard sl(mSubLock);
+
3361
+
3362 auto it = mStreamMaps[sTransactions].begin();
+
3363 while (it != mStreamMaps[sTransactions].end())
+
3364 {
+
3365 InfoSub::pointer p = it->second.lock();
+
3366
+
3367 if (p)
+
3368 {
+
3369 jvObj.visit(
+
3370 p->getApiVersion(), //
+
3371 [&](Json::Value const& jv) { p->send(jv, true); });
+
3372 ++it;
+
3373 }
+
3374 else
+
3375 it = mStreamMaps[sTransactions].erase(it);
+
3376 }
3377
-
3378 while (it != mStreamMaps[sRTTransactions].end())
-
3379 {
-
3380 InfoSub::pointer p = it->second.lock();
-
3381
-
3382 if (p)
-
3383 {
-
3384 jvObj.visit(
-
3385 p->getApiVersion(), //
-
3386 [&](Json::Value const& jv) { p->send(jv, true); });
-
3387 ++it;
-
3388 }
-
3389 else
-
3390 it = mStreamMaps[sRTTransactions].erase(it);
-
3391 }
-
3392 }
-
3393
-
3394 if (transaction.getResult() == tesSUCCESS)
-
3395 app_.getOrderBookDB().processTxn(ledger, transaction, jvObj);
-
3396
-
3397 pubAccountTransaction(ledger, transaction, last);
-
3398}
-
3399
-
3400void
-
3401NetworkOPsImp::pubAccountTransaction(
-
3402 std::shared_ptr<ReadView const> const& ledger,
-
3403 AcceptedLedgerTx const& transaction,
-
3404 bool last)
-
3405{
-
3406 hash_set<InfoSub::pointer> notify;
-
3407 int iProposed = 0;
-
3408 int iAccepted = 0;
-
3409
-
3410 std::vector<SubAccountHistoryInfo> accountHistoryNotify;
-
3411 auto const currLedgerSeq = ledger->seq();
-
3412 {
-
3413 std::lock_guard sl(mSubLock);
-
3414
-
3415 if (!mSubAccount.empty() || !mSubRTAccount.empty() ||
-
3416 !mSubAccountHistory.empty())
-
3417 {
-
3418 for (auto const& affectedAccount : transaction.getAffected())
-
3419 {
-
3420 if (auto simiIt = mSubRTAccount.find(affectedAccount);
-
3421 simiIt != mSubRTAccount.end())
-
3422 {
-
3423 auto it = simiIt->second.begin();
-
3424
-
3425 while (it != simiIt->second.end())
-
3426 {
-
3427 InfoSub::pointer p = it->second.lock();
-
3428
-
3429 if (p)
-
3430 {
-
3431 notify.insert(p);
-
3432 ++it;
-
3433 ++iProposed;
-
3434 }
-
3435 else
-
3436 it = simiIt->second.erase(it);
-
3437 }
-
3438 }
-
3439
-
3440 if (auto simiIt = mSubAccount.find(affectedAccount);
-
3441 simiIt != mSubAccount.end())
-
3442 {
-
3443 auto it = simiIt->second.begin();
-
3444 while (it != simiIt->second.end())
-
3445 {
-
3446 InfoSub::pointer p = it->second.lock();
-
3447
-
3448 if (p)
-
3449 {
-
3450 notify.insert(p);
-
3451 ++it;
-
3452 ++iAccepted;
-
3453 }
-
3454 else
-
3455 it = simiIt->second.erase(it);
-
3456 }
-
3457 }
-
3458
-
3459 if (auto histoIt = mSubAccountHistory.find(affectedAccount);
-
3460 histoIt != mSubAccountHistory.end())
-
3461 {
-
3462 auto& subs = histoIt->second;
-
3463 auto it = subs.begin();
-
3464 while (it != subs.end())
-
3465 {
-
3466 SubAccountHistoryInfoWeak const& info = it->second;
-
3467 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
-
3468 {
-
3469 ++it;
-
3470 continue;
-
3471 }
-
3472
-
3473 if (auto isSptr = info.sinkWptr_.lock(); isSptr)
-
3474 {
-
3475 accountHistoryNotify.emplace_back(
-
3476 SubAccountHistoryInfo{isSptr, info.index_});
-
3477 ++it;
-
3478 }
-
3479 else
-
3480 {
-
3481 it = subs.erase(it);
-
3482 }
-
3483 }
-
3484 if (subs.empty())
-
3485 mSubAccountHistory.erase(histoIt);
-
3486 }
-
3487 }
-
3488 }
-
3489 }
-
3490
-
3491 JLOG(m_journal.trace())
-
3492 << "pubAccountTransaction: "
-
3493 << "proposed=" << iProposed << ", accepted=" << iAccepted;
-
3494
-
3495 if (!notify.empty() || !accountHistoryNotify.empty())
-
3496 {
-
3497 auto const& stTxn = transaction.getTxn();
-
3498
-
3499 // Create two different Json objects, for different API versions
-
3500 auto const metaRef = std::ref(transaction.getMeta());
-
3501 auto const trResult = transaction.getResult();
-
3502 MultiApiJson jvObj = transJson(stTxn, trResult, true, ledger, metaRef);
-
3503
-
3504 for (InfoSub::ref isrListener : notify)
-
3505 {
-
3506 jvObj.visit(
-
3507 isrListener->getApiVersion(), //
-
3508 [&](Json::Value const& jv) { isrListener->send(jv, true); });
-
3509 }
-
3510
-
3511 if (last)
-
3512 jvObj.set(jss::account_history_boundary, true);
-
3513
-
3514 XRPL_ASSERT(
-
3515 jvObj.isMember(jss::account_history_tx_stream) ==
-
3516 MultiApiJson::none,
-
3517 "ripple::NetworkOPsImp::pubAccountTransaction : "
-
3518 "account_history_tx_stream not set");
-
3519 for (auto& info : accountHistoryNotify)
-
3520 {
-
3521 auto& index = info.index_;
-
3522 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
-
3523 jvObj.set(jss::account_history_tx_first, true);
-
3524
-
3525 jvObj.set(jss::account_history_tx_index, index->forwardTxIndex_++);
+
3378 it = mStreamMaps[sRTTransactions].begin();
+
3379
+
3380 while (it != mStreamMaps[sRTTransactions].end())
+
3381 {
+
3382 InfoSub::pointer p = it->second.lock();
+
3383
+
3384 if (p)
+
3385 {
+
3386 jvObj.visit(
+
3387 p->getApiVersion(), //
+
3388 [&](Json::Value const& jv) { p->send(jv, true); });
+
3389 ++it;
+
3390 }
+
3391 else
+
3392 it = mStreamMaps[sRTTransactions].erase(it);
+
3393 }
+
3394 }
+
3395
+
3396 if (transaction.getResult() == tesSUCCESS)
+
3397 app_.getOrderBookDB().processTxn(ledger, transaction, jvObj);
+
3398
+
3399 pubAccountTransaction(ledger, transaction, last);
+
3400}
+
3401
+
3402void
+
3403NetworkOPsImp::pubAccountTransaction(
+
3404 std::shared_ptr<ReadView const> const& ledger,
+
3405 AcceptedLedgerTx const& transaction,
+
3406 bool last)
+
3407{
+
3408 hash_set<InfoSub::pointer> notify;
+
3409 int iProposed = 0;
+
3410 int iAccepted = 0;
+
3411
+
3412 std::vector<SubAccountHistoryInfo> accountHistoryNotify;
+
3413 auto const currLedgerSeq = ledger->seq();
+
3414 {
+
3415 std::lock_guard sl(mSubLock);
+
3416
+
3417 if (!mSubAccount.empty() || !mSubRTAccount.empty() ||
+
3418 !mSubAccountHistory.empty())
+
3419 {
+
3420 for (auto const& affectedAccount : transaction.getAffected())
+
3421 {
+
3422 if (auto simiIt = mSubRTAccount.find(affectedAccount);
+
3423 simiIt != mSubRTAccount.end())
+
3424 {
+
3425 auto it = simiIt->second.begin();
+
3426
+
3427 while (it != simiIt->second.end())
+
3428 {
+
3429 InfoSub::pointer p = it->second.lock();
+
3430
+
3431 if (p)
+
3432 {
+
3433 notify.insert(p);
+
3434 ++it;
+
3435 ++iProposed;
+
3436 }
+
3437 else
+
3438 it = simiIt->second.erase(it);
+
3439 }
+
3440 }
+
3441
+
3442 if (auto simiIt = mSubAccount.find(affectedAccount);
+
3443 simiIt != mSubAccount.end())
+
3444 {
+
3445 auto it = simiIt->second.begin();
+
3446 while (it != simiIt->second.end())
+
3447 {
+
3448 InfoSub::pointer p = it->second.lock();
+
3449
+
3450 if (p)
+
3451 {
+
3452 notify.insert(p);
+
3453 ++it;
+
3454 ++iAccepted;
+
3455 }
+
3456 else
+
3457 it = simiIt->second.erase(it);
+
3458 }
+
3459 }
+
3460
+
3461 if (auto histoIt = mSubAccountHistory.find(affectedAccount);
+
3462 histoIt != mSubAccountHistory.end())
+
3463 {
+
3464 auto& subs = histoIt->second;
+
3465 auto it = subs.begin();
+
3466 while (it != subs.end())
+
3467 {
+
3468 SubAccountHistoryInfoWeak const& info = it->second;
+
3469 if (currLedgerSeq <= info.index_->separationLedgerSeq_)
+
3470 {
+
3471 ++it;
+
3472 continue;
+
3473 }
+
3474
+
3475 if (auto isSptr = info.sinkWptr_.lock(); isSptr)
+
3476 {
+
3477 accountHistoryNotify.emplace_back(
+
3478 SubAccountHistoryInfo{isSptr, info.index_});
+
3479 ++it;
+
3480 }
+
3481 else
+
3482 {
+
3483 it = subs.erase(it);
+
3484 }
+
3485 }
+
3486 if (subs.empty())
+
3487 mSubAccountHistory.erase(histoIt);
+
3488 }
+
3489 }
+
3490 }
+
3491 }
+
3492
+
3493 JLOG(m_journal.trace())
+
3494 << "pubAccountTransaction: "
+
3495 << "proposed=" << iProposed << ", accepted=" << iAccepted;
+
3496
+
3497 if (!notify.empty() || !accountHistoryNotify.empty())
+
3498 {
+
3499 auto const& stTxn = transaction.getTxn();
+
3500
+
3501 // Create two different Json objects, for different API versions
+
3502 auto const metaRef = std::ref(transaction.getMeta());
+
3503 auto const trResult = transaction.getResult();
+
3504 MultiApiJson jvObj = transJson(stTxn, trResult, true, ledger, metaRef);
+
3505
+
3506 for (InfoSub::ref isrListener : notify)
+
3507 {
+
3508 jvObj.visit(
+
3509 isrListener->getApiVersion(), //
+
3510 [&](Json::Value const& jv) { isrListener->send(jv, true); });
+
3511 }
+
3512
+
3513 if (last)
+
3514 jvObj.set(jss::account_history_boundary, true);
+
3515
+
3516 XRPL_ASSERT(
+
3517 jvObj.isMember(jss::account_history_tx_stream) ==
+
3518 MultiApiJson::none,
+
3519 "ripple::NetworkOPsImp::pubAccountTransaction : "
+
3520 "account_history_tx_stream not set");
+
3521 for (auto& info : accountHistoryNotify)
+
3522 {
+
3523 auto& index = info.index_;
+
3524 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
+
3525 jvObj.set(jss::account_history_tx_first, true);
3526
-
3527 jvObj.visit(
-
3528 info.sink_->getApiVersion(), //
-
3529 [&](Json::Value const& jv) { info.sink_->send(jv, true); });
-
3530 }
-
3531 }
-
3532}
-
3533
-
3534void
-
3535NetworkOPsImp::pubProposedAccountTransaction(
-
3536 std::shared_ptr<ReadView const> const& ledger,
-
3537 std::shared_ptr<STTx const> const& tx,
-
3538 TER result)
-
3539{
-
3540 hash_set<InfoSub::pointer> notify;
-
3541 int iProposed = 0;
-
3542
-
3543 std::vector<SubAccountHistoryInfo> accountHistoryNotify;
+
3527 jvObj.set(jss::account_history_tx_index, index->forwardTxIndex_++);
+
3528
+
3529 jvObj.visit(
+
3530 info.sink_->getApiVersion(), //
+
3531 [&](Json::Value const& jv) { info.sink_->send(jv, true); });
+
3532 }
+
3533 }
+
3534}
+
3535
+
3536void
+
3537NetworkOPsImp::pubProposedAccountTransaction(
+
3538 std::shared_ptr<ReadView const> const& ledger,
+
3539 std::shared_ptr<STTx const> const& tx,
+
3540 TER result)
+
3541{
+
3542 hash_set<InfoSub::pointer> notify;
+
3543 int iProposed = 0;
3544
-
3545 {
-
3546 std::lock_guard sl(mSubLock);
-
3547
-
3548 if (mSubRTAccount.empty())
-
3549 return;
-
3550
-
3551 if (!mSubAccount.empty() || !mSubRTAccount.empty() ||
-
3552 !mSubAccountHistory.empty())
-
3553 {
-
3554 for (auto const& affectedAccount : tx->getMentionedAccounts())
-
3555 {
-
3556 if (auto simiIt = mSubRTAccount.find(affectedAccount);
-
3557 simiIt != mSubRTAccount.end())
-
3558 {
-
3559 auto it = simiIt->second.begin();
-
3560
-
3561 while (it != simiIt->second.end())
-
3562 {
-
3563 InfoSub::pointer p = it->second.lock();
-
3564
-
3565 if (p)
-
3566 {
-
3567 notify.insert(p);
-
3568 ++it;
-
3569 ++iProposed;
-
3570 }
-
3571 else
-
3572 it = simiIt->second.erase(it);
-
3573 }
-
3574 }
-
3575 }
-
3576 }
-
3577 }
-
3578
-
3579 JLOG(m_journal.trace()) << "pubProposedAccountTransaction: " << iProposed;
+
3545 std::vector<SubAccountHistoryInfo> accountHistoryNotify;
+
3546
+
3547 {
+
3548 std::lock_guard sl(mSubLock);
+
3549
+
3550 if (mSubRTAccount.empty())
+
3551 return;
+
3552
+
3553 if (!mSubAccount.empty() || !mSubRTAccount.empty() ||
+
3554 !mSubAccountHistory.empty())
+
3555 {
+
3556 for (auto const& affectedAccount : tx->getMentionedAccounts())
+
3557 {
+
3558 if (auto simiIt = mSubRTAccount.find(affectedAccount);
+
3559 simiIt != mSubRTAccount.end())
+
3560 {
+
3561 auto it = simiIt->second.begin();
+
3562
+
3563 while (it != simiIt->second.end())
+
3564 {
+
3565 InfoSub::pointer p = it->second.lock();
+
3566
+
3567 if (p)
+
3568 {
+
3569 notify.insert(p);
+
3570 ++it;
+
3571 ++iProposed;
+
3572 }
+
3573 else
+
3574 it = simiIt->second.erase(it);
+
3575 }
+
3576 }
+
3577 }
+
3578 }
+
3579 }
3580
-
3581 if (!notify.empty() || !accountHistoryNotify.empty())
-
3582 {
-
3583 // Create two different Json objects, for different API versions
-
3584 MultiApiJson jvObj = transJson(tx, result, false, ledger, std::nullopt);
-
3585
-
3586 for (InfoSub::ref isrListener : notify)
-
3587 jvObj.visit(
-
3588 isrListener->getApiVersion(), //
-
3589 [&](Json::Value const& jv) { isrListener->send(jv, true); });
-
3590
-
3591 XRPL_ASSERT(
-
3592 jvObj.isMember(jss::account_history_tx_stream) ==
-
3593 MultiApiJson::none,
-
3594 "ripple::NetworkOPs::pubProposedAccountTransaction : "
-
3595 "account_history_tx_stream not set");
-
3596 for (auto& info : accountHistoryNotify)
-
3597 {
-
3598 auto& index = info.index_;
-
3599 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
-
3600 jvObj.set(jss::account_history_tx_first, true);
-
3601 jvObj.set(jss::account_history_tx_index, index->forwardTxIndex_++);
-
3602 jvObj.visit(
-
3603 info.sink_->getApiVersion(), //
-
3604 [&](Json::Value const& jv) { info.sink_->send(jv, true); });
-
3605 }
-
3606 }
-
3607}
-
3608
-
3609//
-
3610// Monitoring
+
3581 JLOG(m_journal.trace()) << "pubProposedAccountTransaction: " << iProposed;
+
3582
+
3583 if (!notify.empty() || !accountHistoryNotify.empty())
+
3584 {
+
3585 // Create two different Json objects, for different API versions
+
3586 MultiApiJson jvObj = transJson(tx, result, false, ledger, std::nullopt);
+
3587
+
3588 for (InfoSub::ref isrListener : notify)
+
3589 jvObj.visit(
+
3590 isrListener->getApiVersion(), //
+
3591 [&](Json::Value const& jv) { isrListener->send(jv, true); });
+
3592
+
3593 XRPL_ASSERT(
+
3594 jvObj.isMember(jss::account_history_tx_stream) ==
+
3595 MultiApiJson::none,
+
3596 "ripple::NetworkOPs::pubProposedAccountTransaction : "
+
3597 "account_history_tx_stream not set");
+
3598 for (auto& info : accountHistoryNotify)
+
3599 {
+
3600 auto& index = info.index_;
+
3601 if (index->forwardTxIndex_ == 0 && !index->haveHistorical_)
+
3602 jvObj.set(jss::account_history_tx_first, true);
+
3603 jvObj.set(jss::account_history_tx_index, index->forwardTxIndex_++);
+
3604 jvObj.visit(
+
3605 info.sink_->getApiVersion(), //
+
3606 [&](Json::Value const& jv) { info.sink_->send(jv, true); });
+
3607 }
+
3608 }
+
3609}
+
3610
3611//
-
3612
-
3613void
-
3614NetworkOPsImp::subAccount(
-
3615 InfoSub::ref isrListener,
-
3616 hash_set<AccountID> const& vnaAccountIDs,
-
3617 bool rt)
-
3618{
-
3619 SubInfoMapType& subMap = rt ? mSubRTAccount : mSubAccount;
-
3620
-
3621 for (auto const& naAccountID : vnaAccountIDs)
-
3622 {
-
3623 JLOG(m_journal.trace())
-
3624 << "subAccount: account: " << toBase58(naAccountID);
-
3625
-
3626 isrListener->insertSubAccountInfo(naAccountID, rt);
-
3627 }
-
3628
-
3629 std::lock_guard sl(mSubLock);
+
3612// Monitoring
+
3613//
+
3614
+
3615void
+
3616NetworkOPsImp::subAccount(
+
3617 InfoSub::ref isrListener,
+
3618 hash_set<AccountID> const& vnaAccountIDs,
+
3619 bool rt)
+
3620{
+
3621 SubInfoMapType& subMap = rt ? mSubRTAccount : mSubAccount;
+
3622
+
3623 for (auto const& naAccountID : vnaAccountIDs)
+
3624 {
+
3625 JLOG(m_journal.trace())
+
3626 << "subAccount: account: " << toBase58(naAccountID);
+
3627
+
3628 isrListener->insertSubAccountInfo(naAccountID, rt);
+
3629 }
3630
-
3631 for (auto const& naAccountID : vnaAccountIDs)
-
3632 {
-
3633 auto simIterator = subMap.find(naAccountID);
-
3634 if (simIterator == subMap.end())
-
3635 {
-
3636 // Not found, note that account has a new single listner.
-
3637 SubMapType usisElement;
-
3638 usisElement[isrListener->getSeq()] = isrListener;
-
3639 // VFALCO NOTE This is making a needless copy of naAccountID
-
3640 subMap.insert(simIterator, make_pair(naAccountID, usisElement));
-
3641 }
-
3642 else
-
3643 {
-
3644 // Found, note that the account has another listener.
-
3645 simIterator->second[isrListener->getSeq()] = isrListener;
-
3646 }
-
3647 }
-
3648}
-
3649
-
3650void
-
3651NetworkOPsImp::unsubAccount(
-
3652 InfoSub::ref isrListener,
-
3653 hash_set<AccountID> const& vnaAccountIDs,
-
3654 bool rt)
-
3655{
-
3656 for (auto const& naAccountID : vnaAccountIDs)
-
3657 {
-
3658 // Remove from the InfoSub
-
3659 isrListener->deleteSubAccountInfo(naAccountID, rt);
-
3660 }
-
3661
-
3662 // Remove from the server
-
3663 unsubAccountInternal(isrListener->getSeq(), vnaAccountIDs, rt);
-
3664}
-
3665
-
3666void
-
3667NetworkOPsImp::unsubAccountInternal(
-
3668 std::uint64_t uSeq,
-
3669 hash_set<AccountID> const& vnaAccountIDs,
-
3670 bool rt)
-
3671{
-
3672 std::lock_guard sl(mSubLock);
-
3673
-
3674 SubInfoMapType& subMap = rt ? mSubRTAccount : mSubAccount;
+
3631 std::lock_guard sl(mSubLock);
+
3632
+
3633 for (auto const& naAccountID : vnaAccountIDs)
+
3634 {
+
3635 auto simIterator = subMap.find(naAccountID);
+
3636 if (simIterator == subMap.end())
+
3637 {
+
3638 // Not found, note that account has a new single listner.
+
3639 SubMapType usisElement;
+
3640 usisElement[isrListener->getSeq()] = isrListener;
+
3641 // VFALCO NOTE This is making a needless copy of naAccountID
+
3642 subMap.insert(simIterator, make_pair(naAccountID, usisElement));
+
3643 }
+
3644 else
+
3645 {
+
3646 // Found, note that the account has another listener.
+
3647 simIterator->second[isrListener->getSeq()] = isrListener;
+
3648 }
+
3649 }
+
3650}
+
3651
+
3652void
+
3653NetworkOPsImp::unsubAccount(
+
3654 InfoSub::ref isrListener,
+
3655 hash_set<AccountID> const& vnaAccountIDs,
+
3656 bool rt)
+
3657{
+
3658 for (auto const& naAccountID : vnaAccountIDs)
+
3659 {
+
3660 // Remove from the InfoSub
+
3661 isrListener->deleteSubAccountInfo(naAccountID, rt);
+
3662 }
+
3663
+
3664 // Remove from the server
+
3665 unsubAccountInternal(isrListener->getSeq(), vnaAccountIDs, rt);
+
3666}
+
3667
+
3668void
+
3669NetworkOPsImp::unsubAccountInternal(
+
3670 std::uint64_t uSeq,
+
3671 hash_set<AccountID> const& vnaAccountIDs,
+
3672 bool rt)
+
3673{
+
3674 std::lock_guard sl(mSubLock);
3675
-
3676 for (auto const& naAccountID : vnaAccountIDs)
-
3677 {
-
3678 auto simIterator = subMap.find(naAccountID);
-
3679
-
3680 if (simIterator != subMap.end())
-
3681 {
-
3682 // Found
-
3683 simIterator->second.erase(uSeq);
-
3684
-
3685 if (simIterator->second.empty())
-
3686 {
-
3687 // Don't need hash entry.
-
3688 subMap.erase(simIterator);
-
3689 }
-
3690 }
-
3691 }
-
3692}
-
3693
-
3694void
-
3695NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
-
3696{
-
3697 enum DatabaseType { Sqlite, None };
-
3698 static auto const databaseType = [&]() -> DatabaseType {
-
3699 // Use a dynamic_cast to return DatabaseType::None
-
3700 // on failure.
-
3701 if (dynamic_cast<SQLiteDatabase*>(&app_.getRelationalDatabase()))
-
3702 {
-
3703 return DatabaseType::Sqlite;
-
3704 }
-
3705 return DatabaseType::None;
-
3706 }();
-
3707
-
3708 if (databaseType == DatabaseType::None)
-
3709 {
-
3710 JLOG(m_journal.error())
-
3711 << "AccountHistory job for account "
-
3712 << toBase58(subInfo.index_->accountId_) << " no database";
-
3713 if (auto sptr = subInfo.sinkWptr_.lock(); sptr)
-
3714 {
-
3715 sptr->send(rpcError(rpcINTERNAL), true);
-
3716 unsubAccountHistory(sptr, subInfo.index_->accountId_, false);
-
3717 }
-
3718 return;
-
3719 }
-
3720
-
3721 app_.getJobQueue().addJob(
-
3722 jtCLIENT_ACCT_HIST,
-
3723 "AccountHistoryTxStream",
-
3724 [this, dbType = databaseType, subInfo]() {
-
3725 auto const& accountId = subInfo.index_->accountId_;
-
3726 auto& lastLedgerSeq = subInfo.index_->historyLastLedgerSeq_;
-
3727 auto& txHistoryIndex = subInfo.index_->historyTxIndex_;
-
3728
-
3729 JLOG(m_journal.trace())
-
3730 << "AccountHistory job for account " << toBase58(accountId)
-
3731 << " started. lastLedgerSeq=" << lastLedgerSeq;
-
3732
-
3733 auto isFirstTx = [&](std::shared_ptr<Transaction> const& tx,
-
3734 std::shared_ptr<TxMeta> const& meta) -> bool {
-
3735 /*
-
3736 * genesis account: first tx is the one with seq 1
-
3737 * other account: first tx is the one created the account
-
3738 */
-
3739 if (accountId == genesisAccountId)
-
3740 {
-
3741 auto stx = tx->getSTransaction();
-
3742 if (stx->getAccountID(sfAccount) == accountId &&
-
3743 stx->getSeqValue() == 1)
-
3744 return true;
-
3745 }
-
3746
-
3747 for (auto& node : meta->getNodes())
-
3748 {
-
3749 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
-
3750 continue;
-
3751
-
3752 if (node.isFieldPresent(sfNewFields))
-
3753 {
-
3754 if (auto inner = dynamic_cast<STObject const*>(
-
3755 node.peekAtPField(sfNewFields));
-
3756 inner)
-
3757 {
-
3758 if (inner->isFieldPresent(sfAccount) &&
-
3759 inner->getAccountID(sfAccount) == accountId)
-
3760 {
-
3761 return true;
-
3762 }
-
3763 }
-
3764 }
-
3765 }
-
3766
-
3767 return false;
-
3768 };
-
3769
-
3770 auto send = [&](Json::Value const& jvObj,
-
3771 bool unsubscribe) -> bool {
-
3772 if (auto sptr = subInfo.sinkWptr_.lock())
-
3773 {
-
3774 sptr->send(jvObj, true);
-
3775 if (unsubscribe)
-
3776 unsubAccountHistory(sptr, accountId, false);
-
3777 return true;
-
3778 }
-
3779
-
3780 return false;
-
3781 };
-
3782
-
3783 auto sendMultiApiJson = [&](MultiApiJson const& jvObj,
-
3784 bool unsubscribe) -> bool {
-
3785 if (auto sptr = subInfo.sinkWptr_.lock())
-
3786 {
-
3787 jvObj.visit(
-
3788 sptr->getApiVersion(), //
-
3789 [&](Json::Value const& jv) { sptr->send(jv, true); });
-
3790
-
3791 if (unsubscribe)
-
3792 unsubAccountHistory(sptr, accountId, false);
-
3793 return true;
-
3794 }
-
3795
-
3796 return false;
-
3797 };
-
3798
-
3799 auto getMoreTxns =
-
3800 [&](std::uint32_t minLedger,
-
3801 std::uint32_t maxLedger,
-
3802 std::optional<RelationalDatabase::AccountTxMarker> marker)
-
3803 -> std::optional<std::pair<
-
3804 RelationalDatabase::AccountTxs,
-
3805 std::optional<RelationalDatabase::AccountTxMarker>>> {
-
3806 switch (dbType)
-
3807 {
-
3808 case Sqlite: {
-
3809 auto db = static_cast<SQLiteDatabase*>(
-
3810 &app_.getRelationalDatabase());
-
3811 RelationalDatabase::AccountTxPageOptions options{
-
3812 accountId, minLedger, maxLedger, marker, 0, true};
-
3813 return db->newestAccountTxPage(options);
-
3814 }
-
3815 default: {
-
3816 UNREACHABLE(
-
3817 "ripple::NetworkOPsImp::addAccountHistoryJob::"
-
3818 "getMoreTxns : invalid database type");
-
3819 return {};
-
3820 }
-
3821 }
-
3822 };
-
3823
-
3824 /*
-
3825 * search backward until the genesis ledger or asked to stop
-
3826 */
-
3827 while (lastLedgerSeq >= 2 && !subInfo.index_->stopHistorical_)
-
3828 {
-
3829 int feeChargeCount = 0;
-
3830 if (auto sptr = subInfo.sinkWptr_.lock(); sptr)
-
3831 {
-
3832 sptr->getConsumer().charge(Resource::feeMediumBurdenRPC);
-
3833 ++feeChargeCount;
-
3834 }
-
3835 else
-
3836 {
-
3837 JLOG(m_journal.trace())
-
3838 << "AccountHistory job for account "
-
3839 << toBase58(accountId) << " no InfoSub. Fee charged "
-
3840 << feeChargeCount << " times.";
-
3841 return;
-
3842 }
-
3843
-
3844 // try to search in 1024 ledgers till reaching genesis ledgers
-
3845 auto startLedgerSeq =
-
3846 (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
-
3847 JLOG(m_journal.trace())
-
3848 << "AccountHistory job for account " << toBase58(accountId)
-
3849 << ", working on ledger range [" << startLedgerSeq << ","
-
3850 << lastLedgerSeq << "]";
-
3851
-
3852 auto haveRange = [&]() -> bool {
-
3853 std::uint32_t validatedMin = UINT_MAX;
-
3854 std::uint32_t validatedMax = 0;
-
3855 auto haveSomeValidatedLedgers =
-
3856 app_.getLedgerMaster().getValidatedRange(
-
3857 validatedMin, validatedMax);
-
3858
-
3859 return haveSomeValidatedLedgers &&
-
3860 validatedMin <= startLedgerSeq &&
-
3861 lastLedgerSeq <= validatedMax;
-
3862 }();
-
3863
-
3864 if (!haveRange)
-
3865 {
-
3866 JLOG(m_journal.debug())
-
3867 << "AccountHistory reschedule job for account "
-
3868 << toBase58(accountId) << ", incomplete ledger range ["
-
3869 << startLedgerSeq << "," << lastLedgerSeq << "]";
-
3870 setAccountHistoryJobTimer(subInfo);
-
3871 return;
-
3872 }
-
3873
-
3874 std::optional<RelationalDatabase::AccountTxMarker> marker{};
-
3875 while (!subInfo.index_->stopHistorical_)
-
3876 {
-
3877 auto dbResult =
-
3878 getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
-
3879 if (!dbResult)
-
3880 {
-
3881 JLOG(m_journal.debug())
-
3882 << "AccountHistory job for account "
-
3883 << toBase58(accountId) << " getMoreTxns failed.";
-
3884 send(rpcError(rpcINTERNAL), true);
-
3885 return;
-
3886 }
-
3887
-
3888 auto const& txns = dbResult->first;
-
3889 marker = dbResult->second;
-
3890 size_t num_txns = txns.size();
-
3891 for (size_t i = 0; i < num_txns; ++i)
-
3892 {
-
3893 auto const& [tx, meta] = txns[i];
-
3894
-
3895 if (!tx || !meta)
-
3896 {
-
3897 JLOG(m_journal.debug())
-
3898 << "AccountHistory job for account "
-
3899 << toBase58(accountId) << " empty tx or meta.";
-
3900 send(rpcError(rpcINTERNAL), true);
-
3901 return;
-
3902 }
-
3903 auto curTxLedger =
-
3904 app_.getLedgerMaster().getLedgerBySeq(
-
3905 tx->getLedger());
-
3906 if (!curTxLedger)
-
3907 {
-
3908 JLOG(m_journal.debug())
-
3909 << "AccountHistory job for account "
-
3910 << toBase58(accountId) << " no ledger.";
-
3911 send(rpcError(rpcINTERNAL), true);
-
3912 return;
-
3913 }
-
3914 std::shared_ptr<STTx const> stTxn =
-
3915 tx->getSTransaction();
-
3916 if (!stTxn)
-
3917 {
-
3918 JLOG(m_journal.debug())
-
3919 << "AccountHistory job for account "
-
3920 << toBase58(accountId)
-
3921 << " getSTransaction failed.";
-
3922 send(rpcError(rpcINTERNAL), true);
-
3923 return;
-
3924 }
-
3925
-
3926 auto const mRef = std::ref(*meta);
-
3927 auto const trR = meta->getResultTER();
-
3928 MultiApiJson jvTx =
-
3929 transJson(stTxn, trR, true, curTxLedger, mRef);
-
3930
-
3931 jvTx.set(
-
3932 jss::account_history_tx_index, txHistoryIndex--);
-
3933 if (i + 1 == num_txns ||
-
3934 txns[i + 1].first->getLedger() != tx->getLedger())
-
3935 jvTx.set(jss::account_history_boundary, true);
-
3936
-
3937 if (isFirstTx(tx, meta))
-
3938 {
-
3939 jvTx.set(jss::account_history_tx_first, true);
-
3940 sendMultiApiJson(jvTx, false);
-
3941
-
3942 JLOG(m_journal.trace())
-
3943 << "AccountHistory job for account "
-
3944 << toBase58(accountId)
-
3945 << " done, found last tx.";
-
3946 return;
-
3947 }
-
3948 else
-
3949 {
-
3950 sendMultiApiJson(jvTx, false);
-
3951 }
-
3952 }
-
3953
-
3954 if (marker)
-
3955 {
-
3956 JLOG(m_journal.trace())
-
3957 << "AccountHistory job for account "
-
3958 << toBase58(accountId)
-
3959 << " paging, marker=" << marker->ledgerSeq << ":"
-
3960 << marker->txnSeq;
-
3961 }
-
3962 else
-
3963 {
-
3964 break;
-
3965 }
-
3966 }
-
3967
-
3968 if (!subInfo.index_->stopHistorical_)
-
3969 {
-
3970 lastLedgerSeq = startLedgerSeq - 1;
-
3971 if (lastLedgerSeq <= 1)
-
3972 {
-
3973 JLOG(m_journal.trace())
-
3974 << "AccountHistory job for account "
-
3975 << toBase58(accountId)
-
3976 << " done, reached genesis ledger.";
-
3977 return;
-
3978 }
-
3979 }
-
3980 }
-
3981 });
-
3982}
-
3983
-
3984void
-
3985NetworkOPsImp::subAccountHistoryStart(
-
3986 std::shared_ptr<ReadView const> const& ledger,
-
3987 SubAccountHistoryInfoWeak& subInfo)
-
3988{
-
3989 subInfo.index_->separationLedgerSeq_ = ledger->seq();
-
3990 auto const& accountId = subInfo.index_->accountId_;
-
3991 auto const accountKeylet = keylet::account(accountId);
-
3992 if (!ledger->exists(accountKeylet))
-
3993 {
-
3994 JLOG(m_journal.debug())
-
3995 << "subAccountHistoryStart, no account " << toBase58(accountId)
-
3996 << ", no need to add AccountHistory job.";
-
3997 return;
-
3998 }
-
3999 if (accountId == genesisAccountId)
-
4000 {
-
4001 if (auto const sleAcct = ledger->read(accountKeylet); sleAcct)
-
4002 {
-
4003 if (sleAcct->getFieldU32(sfSequence) == 1)
-
4004 {
-
4005 JLOG(m_journal.debug())
-
4006 << "subAccountHistoryStart, genesis account "
-
4007 << toBase58(accountId)
-
4008 << " does not have tx, no need to add AccountHistory job.";
-
4009 return;
-
4010 }
-
4011 }
-
4012 else
-
4013 {
-
4014 UNREACHABLE(
-
4015 "ripple::NetworkOPsImp::subAccountHistoryStart : failed to "
-
4016 "access genesis account");
-
4017 return;
-
4018 }
-
4019 }
-
4020 subInfo.index_->historyLastLedgerSeq_ = ledger->seq();
-
4021 subInfo.index_->haveHistorical_ = true;
-
4022
-
4023 JLOG(m_journal.debug())
-
4024 << "subAccountHistoryStart, add AccountHistory job: accountId="
-
4025 << toBase58(accountId) << ", currentLedgerSeq=" << ledger->seq();
-
4026
-
4027 addAccountHistoryJob(subInfo);
-
4028}
-
4029
-
4030error_code_i
-
4031NetworkOPsImp::subAccountHistory(
-
4032 InfoSub::ref isrListener,
-
4033 AccountID const& accountId)
-
4034{
-
4035 if (!isrListener->insertSubAccountHistory(accountId))
-
4036 {
-
4037 JLOG(m_journal.debug())
-
4038 << "subAccountHistory, already subscribed to account "
-
4039 << toBase58(accountId);
-
4040 return rpcINVALID_PARAMS;
-
4041 }
-
4042
-
4043 std::lock_guard sl(mSubLock);
-
4044 SubAccountHistoryInfoWeak ahi{
-
4045 isrListener, std::make_shared<SubAccountHistoryIndex>(accountId)};
-
4046 auto simIterator = mSubAccountHistory.find(accountId);
-
4047 if (simIterator == mSubAccountHistory.end())
-
4048 {
-
4049 hash_map<std::uint64_t, SubAccountHistoryInfoWeak> inner;
-
4050 inner.emplace(isrListener->getSeq(), ahi);
-
4051 mSubAccountHistory.insert(
-
4052 simIterator, std::make_pair(accountId, inner));
-
4053 }
-
4054 else
-
4055 {
-
4056 simIterator->second.emplace(isrListener->getSeq(), ahi);
-
4057 }
-
4058
-
4059 auto const ledger = app_.getLedgerMaster().getValidatedLedger();
-
4060 if (ledger)
-
4061 {
-
4062 subAccountHistoryStart(ledger, ahi);
-
4063 }
-
4064 else
-
4065 {
-
4066 // The node does not have validated ledgers, so wait for
-
4067 // one before start streaming.
-
4068 // In this case, the subscription is also considered successful.
-
4069 JLOG(m_journal.debug())
-
4070 << "subAccountHistory, no validated ledger yet, delay start";
-
4071 }
-
4072
-
4073 return rpcSUCCESS;
-
4074}
-
4075
-
4076void
-
4077NetworkOPsImp::unsubAccountHistory(
-
4078 InfoSub::ref isrListener,
-
4079 AccountID const& account,
-
4080 bool historyOnly)
-
4081{
-
4082 if (!historyOnly)
-
4083 isrListener->deleteSubAccountHistory(account);
-
4084 unsubAccountHistoryInternal(isrListener->getSeq(), account, historyOnly);
-
4085}
-
4086
-
4087void
-
4088NetworkOPsImp::unsubAccountHistoryInternal(
-
4089 std::uint64_t seq,
-
4090 AccountID const& account,
-
4091 bool historyOnly)
-
4092{
-
4093 std::lock_guard sl(mSubLock);
-
4094 auto simIterator = mSubAccountHistory.find(account);
-
4095 if (simIterator != mSubAccountHistory.end())
-
4096 {
-
4097 auto& subInfoMap = simIterator->second;
-
4098 auto subInfoIter = subInfoMap.find(seq);
-
4099 if (subInfoIter != subInfoMap.end())
-
4100 {
-
4101 subInfoIter->second.index_->stopHistorical_ = true;
-
4102 }
-
4103
-
4104 if (!historyOnly)
-
4105 {
-
4106 simIterator->second.erase(seq);
-
4107 if (simIterator->second.empty())
-
4108 {
-
4109 mSubAccountHistory.erase(simIterator);
-
4110 }
-
4111 }
-
4112 JLOG(m_journal.debug())
-
4113 << "unsubAccountHistory, account " << toBase58(account)
-
4114 << ", historyOnly = " << (historyOnly ? "true" : "false");
-
4115 }
-
4116}
-
4117
-
4118bool
-
4119NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book)
-
4120{
-
4121 if (auto listeners = app_.getOrderBookDB().makeBookListeners(book))
-
4122 listeners->addSubscriber(isrListener);
-
4123 else
-
4124 UNREACHABLE("ripple::NetworkOPsImp::subBook : null book listeners");
-
4125 return true;
-
4126}
-
4127
-
4128bool
-
4129NetworkOPsImp::unsubBook(std::uint64_t uSeq, Book const& book)
-
4130{
-
4131 if (auto listeners = app_.getOrderBookDB().getBookListeners(book))
-
4132 listeners->removeSubscriber(uSeq);
-
4133
-
4134 return true;
-
4135}
-
4136
-
4137std::uint32_t
-
4138NetworkOPsImp::acceptLedger(
-
4139 std::optional<std::chrono::milliseconds> consensusDelay)
-
4140{
-
4141 // This code-path is exclusively used when the server is in standalone
-
4142 // mode via `ledger_accept`
-
4143 XRPL_ASSERT(
-
4144 m_standalone, "ripple::NetworkOPsImp::acceptLedger : is standalone");
-
4145
-
4146 if (!m_standalone)
-
4147 Throw<std::runtime_error>(
-
4148 "Operation only possible in STANDALONE mode.");
-
4149
-
4150 // FIXME Could we improve on this and remove the need for a specialized
-
4151 // API in Consensus?
-
4152 beginConsensus(m_ledgerMaster.getClosedLedger()->info().hash, {});
-
4153 mConsensus.simulate(app_.timeKeeper().closeTime(), consensusDelay);
-
4154 return m_ledgerMaster.getCurrentLedger()->info().seq;
-
4155}
-
4156
-
4157// <-- bool: true=added, false=already there
-
4158bool
-
4159NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
-
4160{
-
4161 if (auto lpClosed = m_ledgerMaster.getValidatedLedger())
-
4162 {
-
4163 jvResult[jss::ledger_index] = lpClosed->info().seq;
-
4164 jvResult[jss::ledger_hash] = to_string(lpClosed->info().hash);
-
4165 jvResult[jss::ledger_time] = Json::Value::UInt(
-
4166 lpClosed->info().closeTime.time_since_epoch().count());
-
4167 if (!lpClosed->rules().enabled(featureXRPFees))
-
4168 jvResult[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED;
-
4169 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
-
4170 jvResult[jss::reserve_base] =
-
4171 lpClosed->fees().accountReserve(0).jsonClipped();
-
4172 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
-
4173 }
-
4174
-
4175 if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger())
-
4176 {
-
4177 jvResult[jss::validated_ledgers] =
-
4178 app_.getLedgerMaster().getCompleteLedgers();
-
4179 }
-
4180
-
4181 std::lock_guard sl(mSubLock);
-
4182 return mStreamMaps[sLedger]
-
4183 .emplace(isrListener->getSeq(), isrListener)
-
4184 .second;
-
4185}
-
4186
-
4187// <-- bool: true=added, false=already there
-
4188bool
-
4189NetworkOPsImp::subBookChanges(InfoSub::ref isrListener)
-
4190{
-
4191 std::lock_guard sl(mSubLock);
-
4192 return mStreamMaps[sBookChanges]
-
4193 .emplace(isrListener->getSeq(), isrListener)
-
4194 .second;
-
4195}
-
4196
-
4197// <-- bool: true=erased, false=was not there
-
4198bool
-
4199NetworkOPsImp::unsubLedger(std::uint64_t uSeq)
-
4200{
-
4201 std::lock_guard sl(mSubLock);
-
4202 return mStreamMaps[sLedger].erase(uSeq);
-
4203}
-
4204
-
4205// <-- bool: true=erased, false=was not there
-
4206bool
-
4207NetworkOPsImp::unsubBookChanges(std::uint64_t uSeq)
-
4208{
-
4209 std::lock_guard sl(mSubLock);
-
4210 return mStreamMaps[sBookChanges].erase(uSeq);
-
4211}
-
4212
-
4213// <-- bool: true=added, false=already there
-
4214bool
-
4215NetworkOPsImp::subManifests(InfoSub::ref isrListener)
-
4216{
-
4217 std::lock_guard sl(mSubLock);
-
4218 return mStreamMaps[sManifests]
-
4219 .emplace(isrListener->getSeq(), isrListener)
-
4220 .second;
-
4221}
-
4222
-
4223// <-- bool: true=erased, false=was not there
-
4224bool
-
4225NetworkOPsImp::unsubManifests(std::uint64_t uSeq)
-
4226{
-
4227 std::lock_guard sl(mSubLock);
-
4228 return mStreamMaps[sManifests].erase(uSeq);
-
4229}
-
4230
-
4231// <-- bool: true=added, false=already there
-
4232bool
-
4233NetworkOPsImp::subServer(
-
4234 InfoSub::ref isrListener,
-
4235 Json::Value& jvResult,
-
4236 bool admin)
-
4237{
-
4238 uint256 uRandom;
-
4239
-
4240 if (m_standalone)
-
4241 jvResult[jss::stand_alone] = m_standalone;
-
4242
-
4243 // CHECKME: is it necessary to provide a random number here?
-
4244 beast::rngfill(uRandom.begin(), uRandom.size(), crypto_prng());
-
4245
-
4246 auto const& feeTrack = app_.getFeeTrack();
-
4247 jvResult[jss::random] = to_string(uRandom);
-
4248 jvResult[jss::server_status] = strOperatingMode(admin);
-
4249 jvResult[jss::load_base] = feeTrack.getLoadBase();
-
4250 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
-
4251 jvResult[jss::hostid] = getHostId(admin);
-
4252 jvResult[jss::pubkey_node] =
-
4253 toBase58(TokenType::NodePublic, app_.nodeIdentity().first);
-
4254
-
4255 std::lock_guard sl(mSubLock);
-
4256 return mStreamMaps[sServer]
-
4257 .emplace(isrListener->getSeq(), isrListener)
-
4258 .second;
-
4259}
-
4260
-
4261// <-- bool: true=erased, false=was not there
-
4262bool
-
4263NetworkOPsImp::unsubServer(std::uint64_t uSeq)
-
4264{
-
4265 std::lock_guard sl(mSubLock);
-
4266 return mStreamMaps[sServer].erase(uSeq);
-
4267}
-
4268
-
4269// <-- bool: true=added, false=already there
-
4270bool
-
4271NetworkOPsImp::subTransactions(InfoSub::ref isrListener)
-
4272{
-
4273 std::lock_guard sl(mSubLock);
-
4274 return mStreamMaps[sTransactions]
-
4275 .emplace(isrListener->getSeq(), isrListener)
-
4276 .second;
-
4277}
-
4278
-
4279// <-- bool: true=erased, false=was not there
-
4280bool
-
4281NetworkOPsImp::unsubTransactions(std::uint64_t uSeq)
-
4282{
-
4283 std::lock_guard sl(mSubLock);
-
4284 return mStreamMaps[sTransactions].erase(uSeq);
-
4285}
-
4286
-
4287// <-- bool: true=added, false=already there
-
4288bool
-
4289NetworkOPsImp::subRTTransactions(InfoSub::ref isrListener)
-
4290{
-
4291 std::lock_guard sl(mSubLock);
-
4292 return mStreamMaps[sRTTransactions]
-
4293 .emplace(isrListener->getSeq(), isrListener)
-
4294 .second;
-
4295}
-
4296
-
4297// <-- bool: true=erased, false=was not there
-
4298bool
-
4299NetworkOPsImp::unsubRTTransactions(std::uint64_t uSeq)
-
4300{
-
4301 std::lock_guard sl(mSubLock);
-
4302 return mStreamMaps[sRTTransactions].erase(uSeq);
-
4303}
-
4304
-
4305// <-- bool: true=added, false=already there
-
4306bool
-
4307NetworkOPsImp::subValidations(InfoSub::ref isrListener)
-
4308{
-
4309 std::lock_guard sl(mSubLock);
-
4310 return mStreamMaps[sValidations]
-
4311 .emplace(isrListener->getSeq(), isrListener)
-
4312 .second;
-
4313}
-
4314
-
4315void
-
4316NetworkOPsImp::stateAccounting(Json::Value& obj)
-
4317{
-
4318 accounting_.json(obj);
-
4319}
-
4320
-
4321// <-- bool: true=erased, false=was not there
-
4322bool
-
4323NetworkOPsImp::unsubValidations(std::uint64_t uSeq)
-
4324{
-
4325 std::lock_guard sl(mSubLock);
-
4326 return mStreamMaps[sValidations].erase(uSeq);
-
4327}
-
4328
-
4329// <-- bool: true=added, false=already there
-
4330bool
-
4331NetworkOPsImp::subPeerStatus(InfoSub::ref isrListener)
-
4332{
-
4333 std::lock_guard sl(mSubLock);
-
4334 return mStreamMaps[sPeerStatus]
-
4335 .emplace(isrListener->getSeq(), isrListener)
-
4336 .second;
-
4337}
-
4338
-
4339// <-- bool: true=erased, false=was not there
-
4340bool
-
4341NetworkOPsImp::unsubPeerStatus(std::uint64_t uSeq)
-
4342{
-
4343 std::lock_guard sl(mSubLock);
-
4344 return mStreamMaps[sPeerStatus].erase(uSeq);
-
4345}
-
4346
-
4347// <-- bool: true=added, false=already there
-
4348bool
-
4349NetworkOPsImp::subConsensus(InfoSub::ref isrListener)
-
4350{
-
4351 std::lock_guard sl(mSubLock);
-
4352 return mStreamMaps[sConsensusPhase]
-
4353 .emplace(isrListener->getSeq(), isrListener)
-
4354 .second;
-
4355}
-
4356
-
4357// <-- bool: true=erased, false=was not there
-
4358bool
-
4359NetworkOPsImp::unsubConsensus(std::uint64_t uSeq)
-
4360{
-
4361 std::lock_guard sl(mSubLock);
-
4362 return mStreamMaps[sConsensusPhase].erase(uSeq);
-
4363}
-
4364
-
4365InfoSub::pointer
-
4366NetworkOPsImp::findRpcSub(std::string const& strUrl)
-
4367{
-
4368 std::lock_guard sl(mSubLock);
-
4369
-
4370 subRpcMapType::iterator it = mRpcSubMap.find(strUrl);
+
3676 SubInfoMapType& subMap = rt ? mSubRTAccount : mSubAccount;
+
3677
+
3678 for (auto const& naAccountID : vnaAccountIDs)
+
3679 {
+
3680 auto simIterator = subMap.find(naAccountID);
+
3681
+
3682 if (simIterator != subMap.end())
+
3683 {
+
3684 // Found
+
3685 simIterator->second.erase(uSeq);
+
3686
+
3687 if (simIterator->second.empty())
+
3688 {
+
3689 // Don't need hash entry.
+
3690 subMap.erase(simIterator);
+
3691 }
+
3692 }
+
3693 }
+
3694}
+
3695
+
3696void
+
3697NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
+
3698{
+
3699 enum DatabaseType { Sqlite, None };
+
3700 static auto const databaseType = [&]() -> DatabaseType {
+
3701 // Use a dynamic_cast to return DatabaseType::None
+
3702 // on failure.
+
3703 if (dynamic_cast<SQLiteDatabase*>(&app_.getRelationalDatabase()))
+
3704 {
+
3705 return DatabaseType::Sqlite;
+
3706 }
+
3707 return DatabaseType::None;
+
3708 }();
+
3709
+
3710 if (databaseType == DatabaseType::None)
+
3711 {
+
3712 JLOG(m_journal.error())
+
3713 << "AccountHistory job for account "
+
3714 << toBase58(subInfo.index_->accountId_) << " no database";
+
3715 if (auto sptr = subInfo.sinkWptr_.lock(); sptr)
+
3716 {
+
3717 sptr->send(rpcError(rpcINTERNAL), true);
+
3718 unsubAccountHistory(sptr, subInfo.index_->accountId_, false);
+
3719 }
+
3720 return;
+
3721 }
+
3722
+
3723 app_.getJobQueue().addJob(
+
3724 jtCLIENT_ACCT_HIST,
+
3725 "AccountHistoryTxStream",
+
3726 [this, dbType = databaseType, subInfo]() {
+
3727 auto const& accountId = subInfo.index_->accountId_;
+
3728 auto& lastLedgerSeq = subInfo.index_->historyLastLedgerSeq_;
+
3729 auto& txHistoryIndex = subInfo.index_->historyTxIndex_;
+
3730
+
3731 JLOG(m_journal.trace())
+
3732 << "AccountHistory job for account " << toBase58(accountId)
+
3733 << " started. lastLedgerSeq=" << lastLedgerSeq;
+
3734
+
3735 auto isFirstTx = [&](std::shared_ptr<Transaction> const& tx,
+
3736 std::shared_ptr<TxMeta> const& meta) -> bool {
+
3737 /*
+
3738 * genesis account: first tx is the one with seq 1
+
3739 * other account: first tx is the one created the account
+
3740 */
+
3741 if (accountId == genesisAccountId)
+
3742 {
+
3743 auto stx = tx->getSTransaction();
+
3744 if (stx->getAccountID(sfAccount) == accountId &&
+
3745 stx->getSeqValue() == 1)
+
3746 return true;
+
3747 }
+
3748
+
3749 for (auto& node : meta->getNodes())
+
3750 {
+
3751 if (node.getFieldU16(sfLedgerEntryType) != ltACCOUNT_ROOT)
+
3752 continue;
+
3753
+
3754 if (node.isFieldPresent(sfNewFields))
+
3755 {
+
3756 if (auto inner = dynamic_cast<STObject const*>(
+
3757 node.peekAtPField(sfNewFields));
+
3758 inner)
+
3759 {
+
3760 if (inner->isFieldPresent(sfAccount) &&
+
3761 inner->getAccountID(sfAccount) == accountId)
+
3762 {
+
3763 return true;
+
3764 }
+
3765 }
+
3766 }
+
3767 }
+
3768
+
3769 return false;
+
3770 };
+
3771
+
3772 auto send = [&](Json::Value const& jvObj,
+
3773 bool unsubscribe) -> bool {
+
3774 if (auto sptr = subInfo.sinkWptr_.lock())
+
3775 {
+
3776 sptr->send(jvObj, true);
+
3777 if (unsubscribe)
+
3778 unsubAccountHistory(sptr, accountId, false);
+
3779 return true;
+
3780 }
+
3781
+
3782 return false;
+
3783 };
+
3784
+
3785 auto sendMultiApiJson = [&](MultiApiJson const& jvObj,
+
3786 bool unsubscribe) -> bool {
+
3787 if (auto sptr = subInfo.sinkWptr_.lock())
+
3788 {
+
3789 jvObj.visit(
+
3790 sptr->getApiVersion(), //
+
3791 [&](Json::Value const& jv) { sptr->send(jv, true); });
+
3792
+
3793 if (unsubscribe)
+
3794 unsubAccountHistory(sptr, accountId, false);
+
3795 return true;
+
3796 }
+
3797
+
3798 return false;
+
3799 };
+
3800
+
3801 auto getMoreTxns =
+
3802 [&](std::uint32_t minLedger,
+
3803 std::uint32_t maxLedger,
+
3804 std::optional<RelationalDatabase::AccountTxMarker> marker)
+
3805 -> std::optional<std::pair<
+
3806 RelationalDatabase::AccountTxs,
+
3807 std::optional<RelationalDatabase::AccountTxMarker>>> {
+
3808 switch (dbType)
+
3809 {
+
3810 case Sqlite: {
+
3811 auto db = static_cast<SQLiteDatabase*>(
+
3812 &app_.getRelationalDatabase());
+
3813 RelationalDatabase::AccountTxPageOptions options{
+
3814 accountId, minLedger, maxLedger, marker, 0, true};
+
3815 return db->newestAccountTxPage(options);
+
3816 }
+
3817 default: {
+
3818 UNREACHABLE(
+
3819 "ripple::NetworkOPsImp::addAccountHistoryJob::"
+
3820 "getMoreTxns : invalid database type");
+
3821 return {};
+
3822 }
+
3823 }
+
3824 };
+
3825
+
3826 /*
+
3827 * search backward until the genesis ledger or asked to stop
+
3828 */
+
3829 while (lastLedgerSeq >= 2 && !subInfo.index_->stopHistorical_)
+
3830 {
+
3831 int feeChargeCount = 0;
+
3832 if (auto sptr = subInfo.sinkWptr_.lock(); sptr)
+
3833 {
+
3834 sptr->getConsumer().charge(Resource::feeMediumBurdenRPC);
+
3835 ++feeChargeCount;
+
3836 }
+
3837 else
+
3838 {
+
3839 JLOG(m_journal.trace())
+
3840 << "AccountHistory job for account "
+
3841 << toBase58(accountId) << " no InfoSub. Fee charged "
+
3842 << feeChargeCount << " times.";
+
3843 return;
+
3844 }
+
3845
+
3846 // try to search in 1024 ledgers till reaching genesis ledgers
+
3847 auto startLedgerSeq =
+
3848 (lastLedgerSeq > 1024 + 2 ? lastLedgerSeq - 1024 : 2);
+
3849 JLOG(m_journal.trace())
+
3850 << "AccountHistory job for account " << toBase58(accountId)
+
3851 << ", working on ledger range [" << startLedgerSeq << ","
+
3852 << lastLedgerSeq << "]";
+
3853
+
3854 auto haveRange = [&]() -> bool {
+
3855 std::uint32_t validatedMin = UINT_MAX;
+
3856 std::uint32_t validatedMax = 0;
+
3857 auto haveSomeValidatedLedgers =
+
3858 app_.getLedgerMaster().getValidatedRange(
+
3859 validatedMin, validatedMax);
+
3860
+
3861 return haveSomeValidatedLedgers &&
+
3862 validatedMin <= startLedgerSeq &&
+
3863 lastLedgerSeq <= validatedMax;
+
3864 }();
+
3865
+
3866 if (!haveRange)
+
3867 {
+
3868 JLOG(m_journal.debug())
+
3869 << "AccountHistory reschedule job for account "
+
3870 << toBase58(accountId) << ", incomplete ledger range ["
+
3871 << startLedgerSeq << "," << lastLedgerSeq << "]";
+
3872 setAccountHistoryJobTimer(subInfo);
+
3873 return;
+
3874 }
+
3875
+
3876 std::optional<RelationalDatabase::AccountTxMarker> marker{};
+
3877 while (!subInfo.index_->stopHistorical_)
+
3878 {
+
3879 auto dbResult =
+
3880 getMoreTxns(startLedgerSeq, lastLedgerSeq, marker);
+
3881 if (!dbResult)
+
3882 {
+
3883 JLOG(m_journal.debug())
+
3884 << "AccountHistory job for account "
+
3885 << toBase58(accountId) << " getMoreTxns failed.";
+
3886 send(rpcError(rpcINTERNAL), true);
+
3887 return;
+
3888 }
+
3889
+
3890 auto const& txns = dbResult->first;
+
3891 marker = dbResult->second;
+
3892 size_t num_txns = txns.size();
+
3893 for (size_t i = 0; i < num_txns; ++i)
+
3894 {
+
3895 auto const& [tx, meta] = txns[i];
+
3896
+
3897 if (!tx || !meta)
+
3898 {
+
3899 JLOG(m_journal.debug())
+
3900 << "AccountHistory job for account "
+
3901 << toBase58(accountId) << " empty tx or meta.";
+
3902 send(rpcError(rpcINTERNAL), true);
+
3903 return;
+
3904 }
+
3905 auto curTxLedger =
+
3906 app_.getLedgerMaster().getLedgerBySeq(
+
3907 tx->getLedger());
+
3908 if (!curTxLedger)
+
3909 {
+
3910 JLOG(m_journal.debug())
+
3911 << "AccountHistory job for account "
+
3912 << toBase58(accountId) << " no ledger.";
+
3913 send(rpcError(rpcINTERNAL), true);
+
3914 return;
+
3915 }
+
3916 std::shared_ptr<STTx const> stTxn =
+
3917 tx->getSTransaction();
+
3918 if (!stTxn)
+
3919 {
+
3920 JLOG(m_journal.debug())
+
3921 << "AccountHistory job for account "
+
3922 << toBase58(accountId)
+
3923 << " getSTransaction failed.";
+
3924 send(rpcError(rpcINTERNAL), true);
+
3925 return;
+
3926 }
+
3927
+
3928 auto const mRef = std::ref(*meta);
+
3929 auto const trR = meta->getResultTER();
+
3930 MultiApiJson jvTx =
+
3931 transJson(stTxn, trR, true, curTxLedger, mRef);
+
3932
+
3933 jvTx.set(
+
3934 jss::account_history_tx_index, txHistoryIndex--);
+
3935 if (i + 1 == num_txns ||
+
3936 txns[i + 1].first->getLedger() != tx->getLedger())
+
3937 jvTx.set(jss::account_history_boundary, true);
+
3938
+
3939 if (isFirstTx(tx, meta))
+
3940 {
+
3941 jvTx.set(jss::account_history_tx_first, true);
+
3942 sendMultiApiJson(jvTx, false);
+
3943
+
3944 JLOG(m_journal.trace())
+
3945 << "AccountHistory job for account "
+
3946 << toBase58(accountId)
+
3947 << " done, found last tx.";
+
3948 return;
+
3949 }
+
3950 else
+
3951 {
+
3952 sendMultiApiJson(jvTx, false);
+
3953 }
+
3954 }
+
3955
+
3956 if (marker)
+
3957 {
+
3958 JLOG(m_journal.trace())
+
3959 << "AccountHistory job for account "
+
3960 << toBase58(accountId)
+
3961 << " paging, marker=" << marker->ledgerSeq << ":"
+
3962 << marker->txnSeq;
+
3963 }
+
3964 else
+
3965 {
+
3966 break;
+
3967 }
+
3968 }
+
3969
+
3970 if (!subInfo.index_->stopHistorical_)
+
3971 {
+
3972 lastLedgerSeq = startLedgerSeq - 1;
+
3973 if (lastLedgerSeq <= 1)
+
3974 {
+
3975 JLOG(m_journal.trace())
+
3976 << "AccountHistory job for account "
+
3977 << toBase58(accountId)
+
3978 << " done, reached genesis ledger.";
+
3979 return;
+
3980 }
+
3981 }
+
3982 }
+
3983 });
+
3984}
+
3985
+
3986void
+
3987NetworkOPsImp::subAccountHistoryStart(
+
3988 std::shared_ptr<ReadView const> const& ledger,
+
3989 SubAccountHistoryInfoWeak& subInfo)
+
3990{
+
3991 subInfo.index_->separationLedgerSeq_ = ledger->seq();
+
3992 auto const& accountId = subInfo.index_->accountId_;
+
3993 auto const accountKeylet = keylet::account(accountId);
+
3994 if (!ledger->exists(accountKeylet))
+
3995 {
+
3996 JLOG(m_journal.debug())
+
3997 << "subAccountHistoryStart, no account " << toBase58(accountId)
+
3998 << ", no need to add AccountHistory job.";
+
3999 return;
+
4000 }
+
4001 if (accountId == genesisAccountId)
+
4002 {
+
4003 if (auto const sleAcct = ledger->read(accountKeylet); sleAcct)
+
4004 {
+
4005 if (sleAcct->getFieldU32(sfSequence) == 1)
+
4006 {
+
4007 JLOG(m_journal.debug())
+
4008 << "subAccountHistoryStart, genesis account "
+
4009 << toBase58(accountId)
+
4010 << " does not have tx, no need to add AccountHistory job.";
+
4011 return;
+
4012 }
+
4013 }
+
4014 else
+
4015 {
+
4016 UNREACHABLE(
+
4017 "ripple::NetworkOPsImp::subAccountHistoryStart : failed to "
+
4018 "access genesis account");
+
4019 return;
+
4020 }
+
4021 }
+
4022 subInfo.index_->historyLastLedgerSeq_ = ledger->seq();
+
4023 subInfo.index_->haveHistorical_ = true;
+
4024
+
4025 JLOG(m_journal.debug())
+
4026 << "subAccountHistoryStart, add AccountHistory job: accountId="
+
4027 << toBase58(accountId) << ", currentLedgerSeq=" << ledger->seq();
+
4028
+
4029 addAccountHistoryJob(subInfo);
+
4030}
+
4031
+
4032error_code_i
+
4033NetworkOPsImp::subAccountHistory(
+
4034 InfoSub::ref isrListener,
+
4035 AccountID const& accountId)
+
4036{
+
4037 if (!isrListener->insertSubAccountHistory(accountId))
+
4038 {
+
4039 JLOG(m_journal.debug())
+
4040 << "subAccountHistory, already subscribed to account "
+
4041 << toBase58(accountId);
+
4042 return rpcINVALID_PARAMS;
+
4043 }
+
4044
+
4045 std::lock_guard sl(mSubLock);
+
4046 SubAccountHistoryInfoWeak ahi{
+
4047 isrListener, std::make_shared<SubAccountHistoryIndex>(accountId)};
+
4048 auto simIterator = mSubAccountHistory.find(accountId);
+
4049 if (simIterator == mSubAccountHistory.end())
+
4050 {
+
4051 hash_map<std::uint64_t, SubAccountHistoryInfoWeak> inner;
+
4052 inner.emplace(isrListener->getSeq(), ahi);
+
4053 mSubAccountHistory.insert(
+
4054 simIterator, std::make_pair(accountId, inner));
+
4055 }
+
4056 else
+
4057 {
+
4058 simIterator->second.emplace(isrListener->getSeq(), ahi);
+
4059 }
+
4060
+
4061 auto const ledger = app_.getLedgerMaster().getValidatedLedger();
+
4062 if (ledger)
+
4063 {
+
4064 subAccountHistoryStart(ledger, ahi);
+
4065 }
+
4066 else
+
4067 {
+
4068 // The node does not have validated ledgers, so wait for
+
4069 // one before start streaming.
+
4070 // In this case, the subscription is also considered successful.
+
4071 JLOG(m_journal.debug())
+
4072 << "subAccountHistory, no validated ledger yet, delay start";
+
4073 }
+
4074
+
4075 return rpcSUCCESS;
+
4076}
+
4077
+
4078void
+
4079NetworkOPsImp::unsubAccountHistory(
+
4080 InfoSub::ref isrListener,
+
4081 AccountID const& account,
+
4082 bool historyOnly)
+
4083{
+
4084 if (!historyOnly)
+
4085 isrListener->deleteSubAccountHistory(account);
+
4086 unsubAccountHistoryInternal(isrListener->getSeq(), account, historyOnly);
+
4087}
+
4088
+
4089void
+
4090NetworkOPsImp::unsubAccountHistoryInternal(
+
4091 std::uint64_t seq,
+
4092 AccountID const& account,
+
4093 bool historyOnly)
+
4094{
+
4095 std::lock_guard sl(mSubLock);
+
4096 auto simIterator = mSubAccountHistory.find(account);
+
4097 if (simIterator != mSubAccountHistory.end())
+
4098 {
+
4099 auto& subInfoMap = simIterator->second;
+
4100 auto subInfoIter = subInfoMap.find(seq);
+
4101 if (subInfoIter != subInfoMap.end())
+
4102 {
+
4103 subInfoIter->second.index_->stopHistorical_ = true;
+
4104 }
+
4105
+
4106 if (!historyOnly)
+
4107 {
+
4108 simIterator->second.erase(seq);
+
4109 if (simIterator->second.empty())
+
4110 {
+
4111 mSubAccountHistory.erase(simIterator);
+
4112 }
+
4113 }
+
4114 JLOG(m_journal.debug())
+
4115 << "unsubAccountHistory, account " << toBase58(account)
+
4116 << ", historyOnly = " << (historyOnly ? "true" : "false");
+
4117 }
+
4118}
+
4119
+
4120bool
+
4121NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book)
+
4122{
+
4123 if (auto listeners = app_.getOrderBookDB().makeBookListeners(book))
+
4124 listeners->addSubscriber(isrListener);
+
4125 else
+
4126 UNREACHABLE("ripple::NetworkOPsImp::subBook : null book listeners");
+
4127 return true;
+
4128}
+
4129
+
4130bool
+
4131NetworkOPsImp::unsubBook(std::uint64_t uSeq, Book const& book)
+
4132{
+
4133 if (auto listeners = app_.getOrderBookDB().getBookListeners(book))
+
4134 listeners->removeSubscriber(uSeq);
+
4135
+
4136 return true;
+
4137}
+
4138
+
4139std::uint32_t
+
4140NetworkOPsImp::acceptLedger(
+
4141 std::optional<std::chrono::milliseconds> consensusDelay)
+
4142{
+
4143 // This code-path is exclusively used when the server is in standalone
+
4144 // mode via `ledger_accept`
+
4145 XRPL_ASSERT(
+
4146 m_standalone, "ripple::NetworkOPsImp::acceptLedger : is standalone");
+
4147
+
4148 if (!m_standalone)
+
4149 Throw<std::runtime_error>(
+
4150 "Operation only possible in STANDALONE mode.");
+
4151
+
4152 // FIXME Could we improve on this and remove the need for a specialized
+
4153 // API in Consensus?
+
4154 beginConsensus(m_ledgerMaster.getClosedLedger()->info().hash, {});
+
4155 mConsensus.simulate(app_.timeKeeper().closeTime(), consensusDelay);
+
4156 return m_ledgerMaster.getCurrentLedger()->info().seq;
+
4157}
+
4158
+
4159// <-- bool: true=added, false=already there
+
4160bool
+
4161NetworkOPsImp::subLedger(InfoSub::ref isrListener, Json::Value& jvResult)
+
4162{
+
4163 if (auto lpClosed = m_ledgerMaster.getValidatedLedger())
+
4164 {
+
4165 jvResult[jss::ledger_index] = lpClosed->info().seq;
+
4166 jvResult[jss::ledger_hash] = to_string(lpClosed->info().hash);
+
4167 jvResult[jss::ledger_time] = Json::Value::UInt(
+
4168 lpClosed->info().closeTime.time_since_epoch().count());
+
4169 if (!lpClosed->rules().enabled(featureXRPFees))
+
4170 jvResult[jss::fee_ref] = Config::FEE_UNITS_DEPRECATED;
+
4171 jvResult[jss::fee_base] = lpClosed->fees().base.jsonClipped();
+
4172 jvResult[jss::reserve_base] =
+
4173 lpClosed->fees().accountReserve(0).jsonClipped();
+
4174 jvResult[jss::reserve_inc] = lpClosed->fees().increment.jsonClipped();
+
4175 }
+
4176
+
4177 if ((mMode >= OperatingMode::SYNCING) && !isNeedNetworkLedger())
+
4178 {
+
4179 jvResult[jss::validated_ledgers] =
+
4180 app_.getLedgerMaster().getCompleteLedgers();
+
4181 }
+
4182
+
4183 std::lock_guard sl(mSubLock);
+
4184 return mStreamMaps[sLedger]
+
4185 .emplace(isrListener->getSeq(), isrListener)
+
4186 .second;
+
4187}
+
4188
+
4189// <-- bool: true=added, false=already there
+
4190bool
+
4191NetworkOPsImp::subBookChanges(InfoSub::ref isrListener)
+
4192{
+
4193 std::lock_guard sl(mSubLock);
+
4194 return mStreamMaps[sBookChanges]
+
4195 .emplace(isrListener->getSeq(), isrListener)
+
4196 .second;
+
4197}
+
4198
+
4199// <-- bool: true=erased, false=was not there
+
4200bool
+
4201NetworkOPsImp::unsubLedger(std::uint64_t uSeq)
+
4202{
+
4203 std::lock_guard sl(mSubLock);
+
4204 return mStreamMaps[sLedger].erase(uSeq);
+
4205}
+
4206
+
4207// <-- bool: true=erased, false=was not there
+
4208bool
+
4209NetworkOPsImp::unsubBookChanges(std::uint64_t uSeq)
+
4210{
+
4211 std::lock_guard sl(mSubLock);
+
4212 return mStreamMaps[sBookChanges].erase(uSeq);
+
4213}
+
4214
+
4215// <-- bool: true=added, false=already there
+
4216bool
+
4217NetworkOPsImp::subManifests(InfoSub::ref isrListener)
+
4218{
+
4219 std::lock_guard sl(mSubLock);
+
4220 return mStreamMaps[sManifests]
+
4221 .emplace(isrListener->getSeq(), isrListener)
+
4222 .second;
+
4223}
+
4224
+
4225// <-- bool: true=erased, false=was not there
+
4226bool
+
4227NetworkOPsImp::unsubManifests(std::uint64_t uSeq)
+
4228{
+
4229 std::lock_guard sl(mSubLock);
+
4230 return mStreamMaps[sManifests].erase(uSeq);
+
4231}
+
4232
+
4233// <-- bool: true=added, false=already there
+
4234bool
+
4235NetworkOPsImp::subServer(
+
4236 InfoSub::ref isrListener,
+
4237 Json::Value& jvResult,
+
4238 bool admin)
+
4239{
+
4240 uint256 uRandom;
+
4241
+
4242 if (m_standalone)
+
4243 jvResult[jss::stand_alone] = m_standalone;
+
4244
+
4245 // CHECKME: is it necessary to provide a random number here?
+
4246 beast::rngfill(uRandom.begin(), uRandom.size(), crypto_prng());
+
4247
+
4248 auto const& feeTrack = app_.getFeeTrack();
+
4249 jvResult[jss::random] = to_string(uRandom);
+
4250 jvResult[jss::server_status] = strOperatingMode(admin);
+
4251 jvResult[jss::load_base] = feeTrack.getLoadBase();
+
4252 jvResult[jss::load_factor] = feeTrack.getLoadFactor();
+
4253 jvResult[jss::hostid] = getHostId(admin);
+
4254 jvResult[jss::pubkey_node] =
+
4255 toBase58(TokenType::NodePublic, app_.nodeIdentity().first);
+
4256
+
4257 std::lock_guard sl(mSubLock);
+
4258 return mStreamMaps[sServer]
+
4259 .emplace(isrListener->getSeq(), isrListener)
+
4260 .second;
+
4261}
+
4262
+
4263// <-- bool: true=erased, false=was not there
+
4264bool
+
4265NetworkOPsImp::unsubServer(std::uint64_t uSeq)
+
4266{
+
4267 std::lock_guard sl(mSubLock);
+
4268 return mStreamMaps[sServer].erase(uSeq);
+
4269}
+
4270
+
4271// <-- bool: true=added, false=already there
+
4272bool
+
4273NetworkOPsImp::subTransactions(InfoSub::ref isrListener)
+
4274{
+
4275 std::lock_guard sl(mSubLock);
+
4276 return mStreamMaps[sTransactions]
+
4277 .emplace(isrListener->getSeq(), isrListener)
+
4278 .second;
+
4279}
+
4280
+
4281// <-- bool: true=erased, false=was not there
+
4282bool
+
4283NetworkOPsImp::unsubTransactions(std::uint64_t uSeq)
+
4284{
+
4285 std::lock_guard sl(mSubLock);
+
4286 return mStreamMaps[sTransactions].erase(uSeq);
+
4287}
+
4288
+
4289// <-- bool: true=added, false=already there
+
4290bool
+
4291NetworkOPsImp::subRTTransactions(InfoSub::ref isrListener)
+
4292{
+
4293 std::lock_guard sl(mSubLock);
+
4294 return mStreamMaps[sRTTransactions]
+
4295 .emplace(isrListener->getSeq(), isrListener)
+
4296 .second;
+
4297}
+
4298
+
4299// <-- bool: true=erased, false=was not there
+
4300bool
+
4301NetworkOPsImp::unsubRTTransactions(std::uint64_t uSeq)
+
4302{
+
4303 std::lock_guard sl(mSubLock);
+
4304 return mStreamMaps[sRTTransactions].erase(uSeq);
+
4305}
+
4306
+
4307// <-- bool: true=added, false=already there
+
4308bool
+
4309NetworkOPsImp::subValidations(InfoSub::ref isrListener)
+
4310{
+
4311 std::lock_guard sl(mSubLock);
+
4312 return mStreamMaps[sValidations]
+
4313 .emplace(isrListener->getSeq(), isrListener)
+
4314 .second;
+
4315}
+
4316
+
4317void
+
4318NetworkOPsImp::stateAccounting(Json::Value& obj)
+
4319{
+
4320 accounting_.json(obj);
+
4321}
+
4322
+
4323// <-- bool: true=erased, false=was not there
+
4324bool
+
4325NetworkOPsImp::unsubValidations(std::uint64_t uSeq)
+
4326{
+
4327 std::lock_guard sl(mSubLock);
+
4328 return mStreamMaps[sValidations].erase(uSeq);
+
4329}
+
4330
+
4331// <-- bool: true=added, false=already there
+
4332bool
+
4333NetworkOPsImp::subPeerStatus(InfoSub::ref isrListener)
+
4334{
+
4335 std::lock_guard sl(mSubLock);
+
4336 return mStreamMaps[sPeerStatus]
+
4337 .emplace(isrListener->getSeq(), isrListener)
+
4338 .second;
+
4339}
+
4340
+
4341// <-- bool: true=erased, false=was not there
+
4342bool
+
4343NetworkOPsImp::unsubPeerStatus(std::uint64_t uSeq)
+
4344{
+
4345 std::lock_guard sl(mSubLock);
+
4346 return mStreamMaps[sPeerStatus].erase(uSeq);
+
4347}
+
4348
+
4349// <-- bool: true=added, false=already there
+
4350bool
+
4351NetworkOPsImp::subConsensus(InfoSub::ref isrListener)
+
4352{
+
4353 std::lock_guard sl(mSubLock);
+
4354 return mStreamMaps[sConsensusPhase]
+
4355 .emplace(isrListener->getSeq(), isrListener)
+
4356 .second;
+
4357}
+
4358
+
4359// <-- bool: true=erased, false=was not there
+
4360bool
+
4361NetworkOPsImp::unsubConsensus(std::uint64_t uSeq)
+
4362{
+
4363 std::lock_guard sl(mSubLock);
+
4364 return mStreamMaps[sConsensusPhase].erase(uSeq);
+
4365}
+
4366
+
4367InfoSub::pointer
+
4368NetworkOPsImp::findRpcSub(std::string const& strUrl)
+
4369{
+
4370 std::lock_guard sl(mSubLock);
4371
-
4372 if (it != mRpcSubMap.end())
-
4373 return it->second;
-
4374
-
4375 return InfoSub::pointer();
-
4376}
-
4377
-
4378InfoSub::pointer
-
4379NetworkOPsImp::addRpcSub(std::string const& strUrl, InfoSub::ref rspEntry)
-
4380{
-
4381 std::lock_guard sl(mSubLock);
-
4382
-
4383 mRpcSubMap.emplace(strUrl, rspEntry);
+
4372 subRpcMapType::iterator it = mRpcSubMap.find(strUrl);
+
4373
+
4374 if (it != mRpcSubMap.end())
+
4375 return it->second;
+
4376
+
4377 return InfoSub::pointer();
+
4378}
+
4379
+
4380InfoSub::pointer
+
4381NetworkOPsImp::addRpcSub(std::string const& strUrl, InfoSub::ref rspEntry)
+
4382{
+
4383 std::lock_guard sl(mSubLock);
4384
-
4385 return rspEntry;
-
4386}
-
4387
-
4388bool
-
4389NetworkOPsImp::tryRemoveRpcSub(std::string const& strUrl)
-
4390{
-
4391 std::lock_guard sl(mSubLock);
-
4392 auto pInfo = findRpcSub(strUrl);
-
4393
-
4394 if (!pInfo)
-
4395 return false;
-
4396
-
4397 // check to see if any of the stream maps still hold a weak reference to
-
4398 // this entry before removing
-
4399 for (SubMapType const& map : mStreamMaps)
-
4400 {
-
4401 if (map.find(pInfo->getSeq()) != map.end())
-
4402 return false;
-
4403 }
-
4404 mRpcSubMap.erase(strUrl);
-
4405 return true;
-
4406}
-
4407
-
4408#ifndef USE_NEW_BOOK_PAGE
+
4385 mRpcSubMap.emplace(strUrl, rspEntry);
+
4386
+
4387 return rspEntry;
+
4388}
+
4389
+
4390bool
+
4391NetworkOPsImp::tryRemoveRpcSub(std::string const& strUrl)
+
4392{
+
4393 std::lock_guard sl(mSubLock);
+
4394 auto pInfo = findRpcSub(strUrl);
+
4395
+
4396 if (!pInfo)
+
4397 return false;
+
4398
+
4399 // check to see if any of the stream maps still hold a weak reference to
+
4400 // this entry before removing
+
4401 for (SubMapType const& map : mStreamMaps)
+
4402 {
+
4403 if (map.find(pInfo->getSeq()) != map.end())
+
4404 return false;
+
4405 }
+
4406 mRpcSubMap.erase(strUrl);
+
4407 return true;
+
4408}
4409
-
4410// NIKB FIXME this should be looked at. There's no reason why this shouldn't
-
4411// work, but it demonstrated poor performance.
-
4412//
-
4413void
-
4414NetworkOPsImp::getBookPage(
-
4415 std::shared_ptr<ReadView const>& lpLedger,
-
4416 Book const& book,
-
4417 AccountID const& uTakerID,
-
4418 bool const bProof,
-
4419 unsigned int iLimit,
-
4420 Json::Value const& jvMarker,
-
4421 Json::Value& jvResult)
-
4422{ // CAUTION: This is the old get book page logic
-
4423 Json::Value& jvOffers =
-
4424 (jvResult[jss::offers] = Json::Value(Json::arrayValue));
-
4425
-
4426 std::unordered_map<AccountID, STAmount> umBalance;
-
4427 uint256 const uBookBase = getBookBase(book);
-
4428 uint256 const uBookEnd = getQualityNext(uBookBase);
-
4429 uint256 uTipIndex = uBookBase;
-
4430
-
4431 if (auto stream = m_journal.trace())
-
4432 {
-
4433 stream << "getBookPage:" << book;
-
4434 stream << "getBookPage: uBookBase=" << uBookBase;
-
4435 stream << "getBookPage: uBookEnd=" << uBookEnd;
-
4436 stream << "getBookPage: uTipIndex=" << uTipIndex;
-
4437 }
-
4438
-
4439 ReadView const& view = *lpLedger;
+
4410#ifndef USE_NEW_BOOK_PAGE
+
4411
+
4412// NIKB FIXME this should be looked at. There's no reason why this shouldn't
+
4413// work, but it demonstrated poor performance.
+
4414//
+
4415void
+
4416NetworkOPsImp::getBookPage(
+
4417 std::shared_ptr<ReadView const>& lpLedger,
+
4418 Book const& book,
+
4419 AccountID const& uTakerID,
+
4420 bool const bProof,
+
4421 unsigned int iLimit,
+
4422 Json::Value const& jvMarker,
+
4423 Json::Value& jvResult)
+
4424{ // CAUTION: This is the old get book page logic
+
4425 Json::Value& jvOffers =
+
4426 (jvResult[jss::offers] = Json::Value(Json::arrayValue));
+
4427
+
4428 std::unordered_map<AccountID, STAmount> umBalance;
+
4429 uint256 const uBookBase = getBookBase(book);
+
4430 uint256 const uBookEnd = getQualityNext(uBookBase);
+
4431 uint256 uTipIndex = uBookBase;
+
4432
+
4433 if (auto stream = m_journal.trace())
+
4434 {
+
4435 stream << "getBookPage:" << book;
+
4436 stream << "getBookPage: uBookBase=" << uBookBase;
+
4437 stream << "getBookPage: uBookEnd=" << uBookEnd;
+
4438 stream << "getBookPage: uTipIndex=" << uTipIndex;
+
4439 }
4440
-
4441 bool const bGlobalFreeze = isGlobalFrozen(view, book.out.account) ||
-
4442 isGlobalFrozen(view, book.in.account);
-
4443
-
4444 bool bDone = false;
-
4445 bool bDirectAdvance = true;
-
4446
-
4447 std::shared_ptr<SLE const> sleOfferDir;
-
4448 uint256 offerIndex;
-
4449 unsigned int uBookEntry;
-
4450 STAmount saDirRate;
-
4451
-
4452 auto const rate = transferRate(view, book.out.account);
-
4453 auto viewJ = app_.journal("View");
-
4454
-
4455 while (!bDone && iLimit-- > 0)
-
4456 {
-
4457 if (bDirectAdvance)
-
4458 {
-
4459 bDirectAdvance = false;
-
4460
-
4461 JLOG(m_journal.trace()) << "getBookPage: bDirectAdvance";
+
4441 ReadView const& view = *lpLedger;
+
4442
+
4443 bool const bGlobalFreeze = isGlobalFrozen(view, book.out.account) ||
+
4444 isGlobalFrozen(view, book.in.account);
+
4445
+
4446 bool bDone = false;
+
4447 bool bDirectAdvance = true;
+
4448
+
4449 std::shared_ptr<SLE const> sleOfferDir;
+
4450 uint256 offerIndex;
+
4451 unsigned int uBookEntry;
+
4452 STAmount saDirRate;
+
4453
+
4454 auto const rate = transferRate(view, book.out.account);
+
4455 auto viewJ = app_.journal("View");
+
4456
+
4457 while (!bDone && iLimit-- > 0)
+
4458 {
+
4459 if (bDirectAdvance)
+
4460 {
+
4461 bDirectAdvance = false;
4462
-
4463 auto const ledgerIndex = view.succ(uTipIndex, uBookEnd);
-
4464 if (ledgerIndex)
-
4465 sleOfferDir = view.read(keylet::page(*ledgerIndex));
-
4466 else
-
4467 sleOfferDir.reset();
-
4468
-
4469 if (!sleOfferDir)
-
4470 {
-
4471 JLOG(m_journal.trace()) << "getBookPage: bDone";
-
4472 bDone = true;
-
4473 }
-
4474 else
-
4475 {
-
4476 uTipIndex = sleOfferDir->key();
-
4477 saDirRate = amountFromQuality(getQuality(uTipIndex));
-
4478
-
4479 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
+
4463 JLOG(m_journal.trace()) << "getBookPage: bDirectAdvance";
+
4464
+
4465 auto const ledgerIndex = view.succ(uTipIndex, uBookEnd);
+
4466 if (ledgerIndex)
+
4467 sleOfferDir = view.read(keylet::page(*ledgerIndex));
+
4468 else
+
4469 sleOfferDir.reset();
+
4470
+
4471 if (!sleOfferDir)
+
4472 {
+
4473 JLOG(m_journal.trace()) << "getBookPage: bDone";
+
4474 bDone = true;
+
4475 }
+
4476 else
+
4477 {
+
4478 uTipIndex = sleOfferDir->key();
+
4479 saDirRate = amountFromQuality(getQuality(uTipIndex));
4480
-
4481 JLOG(m_journal.trace())
-
4482 << "getBookPage: uTipIndex=" << uTipIndex;
+
4481 cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
+
4482
4483 JLOG(m_journal.trace())
-
4484 << "getBookPage: offerIndex=" << offerIndex;
-
4485 }
-
4486 }
-
4487
-
4488 if (!bDone)
-
4489 {
-
4490 auto sleOffer = view.read(keylet::offer(offerIndex));
-
4491
-
4492 if (sleOffer)
-
4493 {
-
4494 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
-
4495 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
-
4496 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
-
4497 STAmount saOwnerFunds;
-
4498 bool firstOwnerOffer(true);
-
4499
-
4500 if (book.out.account == uOfferOwnerID)
-
4501 {
-
4502 // If an offer is selling issuer's own IOUs, it is fully
-
4503 // funded.
-
4504 saOwnerFunds = saTakerGets;
-
4505 }
-
4506 else if (bGlobalFreeze)
-
4507 {
-
4508 // If either asset is globally frozen, consider all offers
-
4509 // that aren't ours to be totally unfunded
-
4510 saOwnerFunds.clear(book.out);
-
4511 }
-
4512 else
-
4513 {
-
4514 auto umBalanceEntry = umBalance.find(uOfferOwnerID);
-
4515 if (umBalanceEntry != umBalance.end())
-
4516 {
-
4517 // Found in running balance table.
-
4518
-
4519 saOwnerFunds = umBalanceEntry->second;
-
4520 firstOwnerOffer = false;
-
4521 }
-
4522 else
-
4523 {
-
4524 // Did not find balance in table.
-
4525
-
4526 saOwnerFunds = accountHolds(
-
4527 view,
-
4528 uOfferOwnerID,
-
4529 book.out.currency,
-
4530 book.out.account,
-
4531 fhZERO_IF_FROZEN,
-
4532 viewJ);
-
4533
-
4534 if (saOwnerFunds < beast::zero)
-
4535 {
-
4536 // Treat negative funds as zero.
-
4537
-
4538 saOwnerFunds.clear();
-
4539 }
-
4540 }
-
4541 }
-
4542
-
4543 Json::Value jvOffer = sleOffer->getJson(JsonOptions::none);
+
4484 << "getBookPage: uTipIndex=" << uTipIndex;
+
4485 JLOG(m_journal.trace())
+
4486 << "getBookPage: offerIndex=" << offerIndex;
+
4487 }
+
4488 }
+
4489
+
4490 if (!bDone)
+
4491 {
+
4492 auto sleOffer = view.read(keylet::offer(offerIndex));
+
4493
+
4494 if (sleOffer)
+
4495 {
+
4496 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
+
4497 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
+
4498 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
+
4499 STAmount saOwnerFunds;
+
4500 bool firstOwnerOffer(true);
+
4501
+
4502 if (book.out.account == uOfferOwnerID)
+
4503 {
+
4504 // If an offer is selling issuer's own IOUs, it is fully
+
4505 // funded.
+
4506 saOwnerFunds = saTakerGets;
+
4507 }
+
4508 else if (bGlobalFreeze)
+
4509 {
+
4510 // If either asset is globally frozen, consider all offers
+
4511 // that aren't ours to be totally unfunded
+
4512 saOwnerFunds.clear(book.out);
+
4513 }
+
4514 else
+
4515 {
+
4516 auto umBalanceEntry = umBalance.find(uOfferOwnerID);
+
4517 if (umBalanceEntry != umBalance.end())
+
4518 {
+
4519 // Found in running balance table.
+
4520
+
4521 saOwnerFunds = umBalanceEntry->second;
+
4522 firstOwnerOffer = false;
+
4523 }
+
4524 else
+
4525 {
+
4526 // Did not find balance in table.
+
4527
+
4528 saOwnerFunds = accountHolds(
+
4529 view,
+
4530 uOfferOwnerID,
+
4531 book.out.currency,
+
4532 book.out.account,
+
4533 fhZERO_IF_FROZEN,
+
4534 viewJ);
+
4535
+
4536 if (saOwnerFunds < beast::zero)
+
4537 {
+
4538 // Treat negative funds as zero.
+
4539
+
4540 saOwnerFunds.clear();
+
4541 }
+
4542 }
+
4543 }
4544
-
4545 STAmount saTakerGetsFunded;
-
4546 STAmount saOwnerFundsLimit = saOwnerFunds;
-
4547 Rate offerRate = parityRate;
-
4548
-
4549 if (rate != parityRate
-
4550 // Have a tranfer fee.
-
4551 && uTakerID != book.out.account
-
4552 // Not taking offers of own IOUs.
-
4553 && book.out.account != uOfferOwnerID)
-
4554 // Offer owner not issuing ownfunds
-
4555 {
-
4556 // Need to charge a transfer fee to offer owner.
-
4557 offerRate = rate;
-
4558 saOwnerFundsLimit = divide(saOwnerFunds, offerRate);
-
4559 }
-
4560
-
4561 if (saOwnerFundsLimit >= saTakerGets)
-
4562 {
-
4563 // Sufficient funds no shenanigans.
-
4564 saTakerGetsFunded = saTakerGets;
-
4565 }
-
4566 else
-
4567 {
-
4568 // Only provide, if not fully funded.
-
4569
-
4570 saTakerGetsFunded = saOwnerFundsLimit;
+
4545 Json::Value jvOffer = sleOffer->getJson(JsonOptions::none);
+
4546
+
4547 STAmount saTakerGetsFunded;
+
4548 STAmount saOwnerFundsLimit = saOwnerFunds;
+
4549 Rate offerRate = parityRate;
+
4550
+
4551 if (rate != parityRate
+
4552 // Have a tranfer fee.
+
4553 && uTakerID != book.out.account
+
4554 // Not taking offers of own IOUs.
+
4555 && book.out.account != uOfferOwnerID)
+
4556 // Offer owner not issuing ownfunds
+
4557 {
+
4558 // Need to charge a transfer fee to offer owner.
+
4559 offerRate = rate;
+
4560 saOwnerFundsLimit = divide(saOwnerFunds, offerRate);
+
4561 }
+
4562
+
4563 if (saOwnerFundsLimit >= saTakerGets)
+
4564 {
+
4565 // Sufficient funds no shenanigans.
+
4566 saTakerGetsFunded = saTakerGets;
+
4567 }
+
4568 else
+
4569 {
+
4570 // Only provide, if not fully funded.
4571
-
4572 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
-
4573 std::min(
-
4574 saTakerPays,
-
4575 multiply(
-
4576 saTakerGetsFunded, saDirRate, saTakerPays.issue()))
-
4577 .setJson(jvOffer[jss::taker_pays_funded]);
-
4578 }
-
4579
-
4580 STAmount saOwnerPays = (parityRate == offerRate)
-
4581 ? saTakerGetsFunded
-
4582 : std::min(
-
4583 saOwnerFunds, multiply(saTakerGetsFunded, offerRate));
-
4584
-
4585 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
+
4572 saTakerGetsFunded = saOwnerFundsLimit;
+
4573
+
4574 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
+
4575 std::min(
+
4576 saTakerPays,
+
4577 multiply(
+
4578 saTakerGetsFunded, saDirRate, saTakerPays.issue()))
+
4579 .setJson(jvOffer[jss::taker_pays_funded]);
+
4580 }
+
4581
+
4582 STAmount saOwnerPays = (parityRate == offerRate)
+
4583 ? saTakerGetsFunded
+
4584 : std::min(
+
4585 saOwnerFunds, multiply(saTakerGetsFunded, offerRate));
4586
-
4587 // Include all offers funded and unfunded
-
4588 Json::Value& jvOf = jvOffers.append(jvOffer);
-
4589 jvOf[jss::quality] = saDirRate.getText();
-
4590
-
4591 if (firstOwnerOffer)
-
4592 jvOf[jss::owner_funds] = saOwnerFunds.getText();
-
4593 }
-
4594 else
-
4595 {
-
4596 JLOG(m_journal.warn()) << "Missing offer";
-
4597 }
-
4598
-
4599 if (!cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
-
4600 {
-
4601 bDirectAdvance = true;
-
4602 }
-
4603 else
-
4604 {
-
4605 JLOG(m_journal.trace())
-
4606 << "getBookPage: offerIndex=" << offerIndex;
-
4607 }
-
4608 }
-
4609 }
-
4610
-
4611 // jvResult[jss::marker] = Json::Value(Json::arrayValue);
-
4612 // jvResult[jss::nodes] = Json::Value(Json::arrayValue);
-
4613}
-
4614
-
4615#else
+
4587 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
+
4588
+
4589 // Include all offers funded and unfunded
+
4590 Json::Value& jvOf = jvOffers.append(jvOffer);
+
4591 jvOf[jss::quality] = saDirRate.getText();
+
4592
+
4593 if (firstOwnerOffer)
+
4594 jvOf[jss::owner_funds] = saOwnerFunds.getText();
+
4595 }
+
4596 else
+
4597 {
+
4598 JLOG(m_journal.warn()) << "Missing offer";
+
4599 }
+
4600
+
4601 if (!cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
+
4602 {
+
4603 bDirectAdvance = true;
+
4604 }
+
4605 else
+
4606 {
+
4607 JLOG(m_journal.trace())
+
4608 << "getBookPage: offerIndex=" << offerIndex;
+
4609 }
+
4610 }
+
4611 }
+
4612
+
4613 // jvResult[jss::marker] = Json::Value(Json::arrayValue);
+
4614 // jvResult[jss::nodes] = Json::Value(Json::arrayValue);
+
4615}
4616
-
4617// This is the new code that uses the book iterators
-
4618// It has temporarily been disabled
-
4619
-
4620void
-
4621NetworkOPsImp::getBookPage(
-
4622 std::shared_ptr<ReadView const> lpLedger,
-
4623 Book const& book,
-
4624 AccountID const& uTakerID,
-
4625 bool const bProof,
-
4626 unsigned int iLimit,
-
4627 Json::Value const& jvMarker,
-
4628 Json::Value& jvResult)
-
4629{
-
4630 auto& jvOffers = (jvResult[jss::offers] = Json::Value(Json::arrayValue));
-
4631
-
4632 std::map<AccountID, STAmount> umBalance;
+
4617#else
+
4618
+
4619// This is the new code that uses the book iterators
+
4620// It has temporarily been disabled
+
4621
+
4622void
+
4623NetworkOPsImp::getBookPage(
+
4624 std::shared_ptr<ReadView const> lpLedger,
+
4625 Book const& book,
+
4626 AccountID const& uTakerID,
+
4627 bool const bProof,
+
4628 unsigned int iLimit,
+
4629 Json::Value const& jvMarker,
+
4630 Json::Value& jvResult)
+
4631{
+
4632 auto& jvOffers = (jvResult[jss::offers] = Json::Value(Json::arrayValue));
4633
-
4634 MetaView lesActive(lpLedger, tapNONE, true);
-
4635 OrderBookIterator obIterator(lesActive, book);
-
4636
-
4637 auto const rate = transferRate(lesActive, book.out.account);
+
4634 std::map<AccountID, STAmount> umBalance;
+
4635
+
4636 MetaView lesActive(lpLedger, tapNONE, true);
+
4637 OrderBookIterator obIterator(lesActive, book);
4638
-
4639 bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.out.account) ||
-
4640 lesActive.isGlobalFrozen(book.in.account);
-
4641
-
4642 while (iLimit-- > 0 && obIterator.nextOffer())
-
4643 {
-
4644 SLE::pointer sleOffer = obIterator.getCurrentOffer();
-
4645 if (sleOffer)
-
4646 {
-
4647 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
-
4648 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
-
4649 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
-
4650 STAmount saDirRate = obIterator.getCurrentRate();
-
4651 STAmount saOwnerFunds;
-
4652
-
4653 if (book.out.account == uOfferOwnerID)
-
4654 {
-
4655 // If offer is selling issuer's own IOUs, it is fully funded.
-
4656 saOwnerFunds = saTakerGets;
-
4657 }
-
4658 else if (bGlobalFreeze)
-
4659 {
-
4660 // If either asset is globally frozen, consider all offers
-
4661 // that aren't ours to be totally unfunded
-
4662 saOwnerFunds.clear(book.out);
-
4663 }
-
4664 else
-
4665 {
-
4666 auto umBalanceEntry = umBalance.find(uOfferOwnerID);
-
4667
-
4668 if (umBalanceEntry != umBalance.end())
-
4669 {
-
4670 // Found in running balance table.
-
4671
-
4672 saOwnerFunds = umBalanceEntry->second;
-
4673 }
-
4674 else
-
4675 {
-
4676 // Did not find balance in table.
-
4677
-
4678 saOwnerFunds = lesActive.accountHolds(
-
4679 uOfferOwnerID,
-
4680 book.out.currency,
-
4681 book.out.account,
-
4682 fhZERO_IF_FROZEN);
-
4683
-
4684 if (saOwnerFunds.isNegative())
-
4685 {
-
4686 // Treat negative funds as zero.
-
4687
-
4688 saOwnerFunds.zero();
-
4689 }
-
4690 }
-
4691 }
-
4692
-
4693 Json::Value jvOffer = sleOffer->getJson(JsonOptions::none);
+
4639 auto const rate = transferRate(lesActive, book.out.account);
+
4640
+
4641 bool const bGlobalFreeze = lesActive.isGlobalFrozen(book.out.account) ||
+
4642 lesActive.isGlobalFrozen(book.in.account);
+
4643
+
4644 while (iLimit-- > 0 && obIterator.nextOffer())
+
4645 {
+
4646 SLE::pointer sleOffer = obIterator.getCurrentOffer();
+
4647 if (sleOffer)
+
4648 {
+
4649 auto const uOfferOwnerID = sleOffer->getAccountID(sfAccount);
+
4650 auto const& saTakerGets = sleOffer->getFieldAmount(sfTakerGets);
+
4651 auto const& saTakerPays = sleOffer->getFieldAmount(sfTakerPays);
+
4652 STAmount saDirRate = obIterator.getCurrentRate();
+
4653 STAmount saOwnerFunds;
+
4654
+
4655 if (book.out.account == uOfferOwnerID)
+
4656 {
+
4657 // If offer is selling issuer's own IOUs, it is fully funded.
+
4658 saOwnerFunds = saTakerGets;
+
4659 }
+
4660 else if (bGlobalFreeze)
+
4661 {
+
4662 // If either asset is globally frozen, consider all offers
+
4663 // that aren't ours to be totally unfunded
+
4664 saOwnerFunds.clear(book.out);
+
4665 }
+
4666 else
+
4667 {
+
4668 auto umBalanceEntry = umBalance.find(uOfferOwnerID);
+
4669
+
4670 if (umBalanceEntry != umBalance.end())
+
4671 {
+
4672 // Found in running balance table.
+
4673
+
4674 saOwnerFunds = umBalanceEntry->second;
+
4675 }
+
4676 else
+
4677 {
+
4678 // Did not find balance in table.
+
4679
+
4680 saOwnerFunds = lesActive.accountHolds(
+
4681 uOfferOwnerID,
+
4682 book.out.currency,
+
4683 book.out.account,
+
4684 fhZERO_IF_FROZEN);
+
4685
+
4686 if (saOwnerFunds.isNegative())
+
4687 {
+
4688 // Treat negative funds as zero.
+
4689
+
4690 saOwnerFunds.zero();
+
4691 }
+
4692 }
+
4693 }
4694
-
4695 STAmount saTakerGetsFunded;
-
4696 STAmount saOwnerFundsLimit = saOwnerFunds;
-
4697 Rate offerRate = parityRate;
-
4698
-
4699 if (rate != parityRate
-
4700 // Have a tranfer fee.
-
4701 && uTakerID != book.out.account
-
4702 // Not taking offers of own IOUs.
-
4703 && book.out.account != uOfferOwnerID)
-
4704 // Offer owner not issuing ownfunds
-
4705 {
-
4706 // Need to charge a transfer fee to offer owner.
-
4707 offerRate = rate;
-
4708 saOwnerFundsLimit = divide(saOwnerFunds, offerRate);
-
4709 }
-
4710
-
4711 if (saOwnerFundsLimit >= saTakerGets)
-
4712 {
-
4713 // Sufficient funds no shenanigans.
-
4714 saTakerGetsFunded = saTakerGets;
-
4715 }
-
4716 else
-
4717 {
-
4718 // Only provide, if not fully funded.
-
4719 saTakerGetsFunded = saOwnerFundsLimit;
-
4720
-
4721 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
+
4695 Json::Value jvOffer = sleOffer->getJson(JsonOptions::none);
+
4696
+
4697 STAmount saTakerGetsFunded;
+
4698 STAmount saOwnerFundsLimit = saOwnerFunds;
+
4699 Rate offerRate = parityRate;
+
4700
+
4701 if (rate != parityRate
+
4702 // Have a tranfer fee.
+
4703 && uTakerID != book.out.account
+
4704 // Not taking offers of own IOUs.
+
4705 && book.out.account != uOfferOwnerID)
+
4706 // Offer owner not issuing ownfunds
+
4707 {
+
4708 // Need to charge a transfer fee to offer owner.
+
4709 offerRate = rate;
+
4710 saOwnerFundsLimit = divide(saOwnerFunds, offerRate);
+
4711 }
+
4712
+
4713 if (saOwnerFundsLimit >= saTakerGets)
+
4714 {
+
4715 // Sufficient funds no shenanigans.
+
4716 saTakerGetsFunded = saTakerGets;
+
4717 }
+
4718 else
+
4719 {
+
4720 // Only provide, if not fully funded.
+
4721 saTakerGetsFunded = saOwnerFundsLimit;
4722
-
4723 // TOOD(tom): The result of this expression is not used - what's
-
4724 // going on here?
-
4725 std::min(
-
4726 saTakerPays,
-
4727 multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
-
4728 .setJson(jvOffer[jss::taker_pays_funded]);
-
4729 }
-
4730
-
4731 STAmount saOwnerPays = (parityRate == offerRate)
-
4732 ? saTakerGetsFunded
-
4733 : std::min(
-
4734 saOwnerFunds, multiply(saTakerGetsFunded, offerRate));
-
4735
-
4736 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
+
4723 saTakerGetsFunded.setJson(jvOffer[jss::taker_gets_funded]);
+
4724
+
4725 // TOOD(tom): The result of this expression is not used - what's
+
4726 // going on here?
+
4727 std::min(
+
4728 saTakerPays,
+
4729 multiply(saTakerGetsFunded, saDirRate, saTakerPays.issue()))
+
4730 .setJson(jvOffer[jss::taker_pays_funded]);
+
4731 }
+
4732
+
4733 STAmount saOwnerPays = (parityRate == offerRate)
+
4734 ? saTakerGetsFunded
+
4735 : std::min(
+
4736 saOwnerFunds, multiply(saTakerGetsFunded, offerRate));
4737
-
4738 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
-
4739 {
-
4740 // Only provide funded offers and offers of the taker.
-
4741 Json::Value& jvOf = jvOffers.append(jvOffer);
-
4742 jvOf[jss::quality] = saDirRate.getText();
-
4743 }
-
4744 }
-
4745 }
-
4746
-
4747 // jvResult[jss::marker] = Json::Value(Json::arrayValue);
-
4748 // jvResult[jss::nodes] = Json::Value(Json::arrayValue);
-
4749}
-
4750
-
4751#endif
+
4738 umBalance[uOfferOwnerID] = saOwnerFunds - saOwnerPays;
+
4739
+
4740 if (!saOwnerFunds.isZero() || uOfferOwnerID == uTakerID)
+
4741 {
+
4742 // Only provide funded offers and offers of the taker.
+
4743 Json::Value& jvOf = jvOffers.append(jvOffer);
+
4744 jvOf[jss::quality] = saDirRate.getText();
+
4745 }
+
4746 }
+
4747 }
+
4748
+
4749 // jvResult[jss::marker] = Json::Value(Json::arrayValue);
+
4750 // jvResult[jss::nodes] = Json::Value(Json::arrayValue);
+
4751}
4752
-
4753inline void
-
4754NetworkOPsImp::collect_metrics()
-
4755{
-
4756 auto [counters, mode, start, initialSync] = accounting_.getCounterData();
-
4757 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
-
4758 std::chrono::steady_clock::now() - start);
-
4759 counters[static_cast<std::size_t>(mode)].dur += current;
-
4760
-
4761 std::lock_guard lock(m_statsMutex);
-
4762 m_stats.disconnected_duration.set(
-
4763 counters[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
-
4764 .dur.count());
-
4765 m_stats.connected_duration.set(
-
4766 counters[static_cast<std::size_t>(OperatingMode::CONNECTED)]
-
4767 .dur.count());
-
4768 m_stats.syncing_duration.set(
-
4769 counters[static_cast<std::size_t>(OperatingMode::SYNCING)].dur.count());
-
4770 m_stats.tracking_duration.set(
-
4771 counters[static_cast<std::size_t>(OperatingMode::TRACKING)]
-
4772 .dur.count());
-
4773 m_stats.full_duration.set(
-
4774 counters[static_cast<std::size_t>(OperatingMode::FULL)].dur.count());
-
4775
-
4776 m_stats.disconnected_transitions.set(
-
4777 counters[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
-
4778 .transitions);
-
4779 m_stats.connected_transitions.set(
-
4780 counters[static_cast<std::size_t>(OperatingMode::CONNECTED)]
-
4781 .transitions);
-
4782 m_stats.syncing_transitions.set(
-
4783 counters[static_cast<std::size_t>(OperatingMode::SYNCING)].transitions);
-
4784 m_stats.tracking_transitions.set(
-
4785 counters[static_cast<std::size_t>(OperatingMode::TRACKING)]
-
4786 .transitions);
-
4787 m_stats.full_transitions.set(
-
4788 counters[static_cast<std::size_t>(OperatingMode::FULL)].transitions);
-
4789}
-
4790
-
4791void
-
4792NetworkOPsImp::StateAccounting::mode(OperatingMode om)
-
4793{
-
4794 auto now = std::chrono::steady_clock::now();
-
4795
-
4796 std::lock_guard lock(mutex_);
-
4797 ++counters_[static_cast<std::size_t>(om)].transitions;
-
4798 if (om == OperatingMode::FULL &&
-
4799 counters_[static_cast<std::size_t>(om)].transitions == 1)
-
4800 {
-
4801 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(
-
4802 now - processStart_)
-
4803 .count();
-
4804 }
-
4805 counters_[static_cast<std::size_t>(mode_)].dur +=
-
4806 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
-
4807
-
4808 mode_ = om;
-
4809 start_ = now;
-
4810}
-
4811
-
4812void
-
4813NetworkOPsImp::StateAccounting::json(Json::Value& obj) const
-
4814{
-
4815 auto [counters, mode, start, initialSync] = getCounterData();
-
4816 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
-
4817 std::chrono::steady_clock::now() - start);
-
4818 counters[static_cast<std::size_t>(mode)].dur += current;
-
4819
-
4820 obj[jss::state_accounting] = Json::objectValue;
-
4821 for (std::size_t i = static_cast<std::size_t>(OperatingMode::DISCONNECTED);
-
4822 i <= static_cast<std::size_t>(OperatingMode::FULL);
-
4823 ++i)
-
4824 {
-
4825 obj[jss::state_accounting][states_[i]] = Json::objectValue;
-
4826 auto& state = obj[jss::state_accounting][states_[i]];
-
4827 state[jss::transitions] = std::to_string(counters[i].transitions);
-
4828 state[jss::duration_us] = std::to_string(counters[i].dur.count());
-
4829 }
-
4830 obj[jss::server_state_duration_us] = std::to_string(current.count());
-
4831 if (initialSync)
-
4832 obj[jss::initial_sync_duration_us] = std::to_string(initialSync);
-
4833}
-
4834
-
4835//------------------------------------------------------------------------------
+
4753#endif
+
4754
+
4755inline void
+
4756NetworkOPsImp::collect_metrics()
+
4757{
+
4758 auto [counters, mode, start, initialSync] = accounting_.getCounterData();
+
4759 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
+
4760 std::chrono::steady_clock::now() - start);
+
4761 counters[static_cast<std::size_t>(mode)].dur += current;
+
4762
+
4763 std::lock_guard lock(m_statsMutex);
+
4764 m_stats.disconnected_duration.set(
+
4765 counters[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
+
4766 .dur.count());
+
4767 m_stats.connected_duration.set(
+
4768 counters[static_cast<std::size_t>(OperatingMode::CONNECTED)]
+
4769 .dur.count());
+
4770 m_stats.syncing_duration.set(
+
4771 counters[static_cast<std::size_t>(OperatingMode::SYNCING)].dur.count());
+
4772 m_stats.tracking_duration.set(
+
4773 counters[static_cast<std::size_t>(OperatingMode::TRACKING)]
+
4774 .dur.count());
+
4775 m_stats.full_duration.set(
+
4776 counters[static_cast<std::size_t>(OperatingMode::FULL)].dur.count());
+
4777
+
4778 m_stats.disconnected_transitions.set(
+
4779 counters[static_cast<std::size_t>(OperatingMode::DISCONNECTED)]
+
4780 .transitions);
+
4781 m_stats.connected_transitions.set(
+
4782 counters[static_cast<std::size_t>(OperatingMode::CONNECTED)]
+
4783 .transitions);
+
4784 m_stats.syncing_transitions.set(
+
4785 counters[static_cast<std::size_t>(OperatingMode::SYNCING)].transitions);
+
4786 m_stats.tracking_transitions.set(
+
4787 counters[static_cast<std::size_t>(OperatingMode::TRACKING)]
+
4788 .transitions);
+
4789 m_stats.full_transitions.set(
+
4790 counters[static_cast<std::size_t>(OperatingMode::FULL)].transitions);
+
4791}
+
4792
+
4793void
+
4794NetworkOPsImp::StateAccounting::mode(OperatingMode om)
+
4795{
+
4796 auto now = std::chrono::steady_clock::now();
+
4797
+
4798 std::lock_guard lock(mutex_);
+
4799 ++counters_[static_cast<std::size_t>(om)].transitions;
+
4800 if (om == OperatingMode::FULL &&
+
4801 counters_[static_cast<std::size_t>(om)].transitions == 1)
+
4802 {
+
4803 initialSyncUs_ = std::chrono::duration_cast<std::chrono::microseconds>(
+
4804 now - processStart_)
+
4805 .count();
+
4806 }
+
4807 counters_[static_cast<std::size_t>(mode_)].dur +=
+
4808 std::chrono::duration_cast<std::chrono::microseconds>(now - start_);
+
4809
+
4810 mode_ = om;
+
4811 start_ = now;
+
4812}
+
4813
+
4814void
+
4815NetworkOPsImp::StateAccounting::json(Json::Value& obj) const
+
4816{
+
4817 auto [counters, mode, start, initialSync] = getCounterData();
+
4818 auto const current = std::chrono::duration_cast<std::chrono::microseconds>(
+
4819 std::chrono::steady_clock::now() - start);
+
4820 counters[static_cast<std::size_t>(mode)].dur += current;
+
4821
+
4822 obj[jss::state_accounting] = Json::objectValue;
+
4823 for (std::size_t i = static_cast<std::size_t>(OperatingMode::DISCONNECTED);
+
4824 i <= static_cast<std::size_t>(OperatingMode::FULL);
+
4825 ++i)
+
4826 {
+
4827 obj[jss::state_accounting][states_[i]] = Json::objectValue;
+
4828 auto& state = obj[jss::state_accounting][states_[i]];
+
4829 state[jss::transitions] = std::to_string(counters[i].transitions);
+
4830 state[jss::duration_us] = std::to_string(counters[i].dur.count());
+
4831 }
+
4832 obj[jss::server_state_duration_us] = std::to_string(current.count());
+
4833 if (initialSync)
+
4834 obj[jss::initial_sync_duration_us] = std::to_string(initialSync);
+
4835}
4836
-
4837std::unique_ptr<NetworkOPs>
-
4838make_NetworkOPs(
-
4839 Application& app,
-
4840 NetworkOPs::clock_type& clock,
-
4841 bool standalone,
-
4842 std::size_t minPeerCount,
-
4843 bool startvalid,
-
4844 JobQueue& job_queue,
-
4845 LedgerMaster& ledgerMaster,
-
4846 ValidatorKeys const& validatorKeys,
-
4847 boost::asio::io_service& io_svc,
-
4848 beast::Journal journal,
-
4849 beast::insight::Collector::ptr const& collector)
-
4850{
-
4851 return std::make_unique<NetworkOPsImp>(
-
4852 app,
-
4853 clock,
-
4854 standalone,
-
4855 minPeerCount,
-
4856 startvalid,
-
4857 job_queue,
-
4858 ledgerMaster,
-
4859 validatorKeys,
-
4860 io_svc,
-
4861 journal,
-
4862 collector);
-
4863}
-
4864
-
4865} // namespace ripple
+
4837//------------------------------------------------------------------------------
+
4838
+
4839std::unique_ptr<NetworkOPs>
+
4840make_NetworkOPs(
+
4841 Application& app,
+
4842 NetworkOPs::clock_type& clock,
+
4843 bool standalone,
+
4844 std::size_t minPeerCount,
+
4845 bool startvalid,
+
4846 JobQueue& job_queue,
+
4847 LedgerMaster& ledgerMaster,
+
4848 ValidatorKeys const& validatorKeys,
+
4849 boost::asio::io_service& io_svc,
+
4850 beast::Journal journal,
+
4851 beast::insight::Collector::ptr const& collector)
+
4852{
+
4853 return std::make_unique<NetworkOPsImp>(
+
4854 app,
+
4855 clock,
+
4856 standalone,
+
4857 minPeerCount,
+
4858 startvalid,
+
4859 job_queue,
+
4860 ledgerMaster,
+
4861 validatorKeys,
+
4862 io_svc,
+
4863 journal,
+
4864 collector);
+
4865}
+
4866
+
4867} // namespace ripple
algorithm
std::any_of
T any_of(T... args)
std::array
@@ -4979,179 +4981,179 @@ $(function() {
ripple::LoadManager
Manages load sources.
Definition: LoadManager.h:46
ripple::LoadManager::heartbeat
void heartbeat()
Reset the stall detection timer.
Definition: LoadManager.cpp:64
ripple::ManifestCache::getMasterKey
PublicKey getMasterKey(PublicKey const &pk) const
Returns ephemeral signing key's master public key.
Definition: Manifest.cpp:323
-
ripple::NetworkOPsImp::StateAccounting
State accounting records two attributes for each possible server state: 1) Amount of time spent in ea...
Definition: NetworkOPs.cpp:143
-
ripple::NetworkOPsImp::StateAccounting::mode
void mode(OperatingMode om)
Record state transition.
Definition: NetworkOPs.cpp:4792
-
ripple::NetworkOPsImp::StateAccounting::json
void json(Json::Value &obj) const
Output state counters in JSON format.
Definition: NetworkOPs.cpp:4813
-
ripple::NetworkOPsImp::StateAccounting::counters_
std::array< Counters, 5 > counters_
Definition: NetworkOPs.cpp:153
-
ripple::NetworkOPsImp::StateAccounting::initialSyncUs_
std::uint64_t initialSyncUs_
Definition: NetworkOPs.cpp:158
-
ripple::NetworkOPsImp::StateAccounting::getCounterData
CounterData getCounterData() const
Definition: NetworkOPs.cpp:194
-
ripple::NetworkOPsImp::StateAccounting::start_
std::chrono::steady_clock::time_point start_
Definition: NetworkOPs.cpp:155
-
ripple::NetworkOPsImp::StateAccounting::mutex_
std::mutex mutex_
Definition: NetworkOPs.cpp:154
-
ripple::NetworkOPsImp::StateAccounting::states_
static std::array< Json::StaticString const, 5 > const states_
Definition: NetworkOPs.cpp:159
-
ripple::NetworkOPsImp::StateAccounting::StateAccounting
StateAccounting()
Definition: NetworkOPs.cpp:162
-
ripple::NetworkOPsImp::StateAccounting::processStart_
std::chrono::steady_clock::time_point const processStart_
Definition: NetworkOPs.cpp:157
-
ripple::NetworkOPsImp::StateAccounting::mode_
OperatingMode mode_
Definition: NetworkOPs.cpp:152
-
ripple::NetworkOPsImp::TransactionStatus
Transaction with input flags and results to be applied in batches.
Definition: NetworkOPs.cpp:94
-
ripple::NetworkOPsImp::TransactionStatus::TransactionStatus
TransactionStatus(std::shared_ptr< Transaction > t, bool a, bool l, FailHard f)
Definition: NetworkOPs.cpp:103
-
ripple::NetworkOPsImp::TransactionStatus::admin
bool const admin
Definition: NetworkOPs.cpp:97
-
ripple::NetworkOPsImp::TransactionStatus::applied
bool applied
Definition: NetworkOPs.cpp:100
-
ripple::NetworkOPsImp::TransactionStatus::transaction
std::shared_ptr< Transaction > const transaction
Definition: NetworkOPs.cpp:96
-
ripple::NetworkOPsImp::TransactionStatus::failType
FailHard const failType
Definition: NetworkOPs.cpp:99
-
ripple::NetworkOPsImp::TransactionStatus::result
TER result
Definition: NetworkOPs.cpp:101
-
ripple::NetworkOPsImp::TransactionStatus::local
bool const local
Definition: NetworkOPs.cpp:98
-
ripple::NetworkOPsImp
Definition: NetworkOPs.cpp:88
-
ripple::NetworkOPsImp::processClusterTimer
void processClusterTimer()
Definition: NetworkOPs.cpp:1118
-
ripple::NetworkOPsImp::accountHistoryTxTimer_
boost::asio::steady_timer accountHistoryTxTimer_
Definition: NetworkOPs.cpp:754
-
ripple::NetworkOPsImp::pubProposedTransaction
void pubProposedTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result) override
Definition: NetworkOPs.cpp:3042
-
ripple::NetworkOPsImp::getOperatingMode
OperatingMode getOperatingMode() const override
Definition: NetworkOPs.cpp:889
-
ripple::NetworkOPsImp::strOperatingMode
std::string strOperatingMode(OperatingMode const mode, bool const admin) const override
Definition: NetworkOPs.cpp:1166
-
ripple::NetworkOPsImp::preProcessTransaction
bool preProcessTransaction(std::shared_ptr< Transaction > &transaction)
Definition: NetworkOPs.cpp:1249
-
ripple::NetworkOPsImp::mTransactions
std::vector< TransactionStatus > mTransactions
Definition: NetworkOPs.cpp:801
-
ripple::NetworkOPsImp::unsubBookChanges
bool unsubBookChanges(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4207
-
ripple::NetworkOPsImp::mMode
std::atomic< OperatingMode > mMode
Definition: NetworkOPs.cpp:744
-
ripple::NetworkOPsImp::setHeartbeatTimer
void setHeartbeatTimer()
Definition: NetworkOPs.cpp:992
-
ripple::NetworkOPsImp::getLedgerFetchInfo
Json::Value getLedgerFetchInfo() override
Definition: NetworkOPs.cpp:3036
-
ripple::NetworkOPsImp::isUNLBlocked
bool isUNLBlocked() override
Definition: NetworkOPs.cpp:1851
-
ripple::NetworkOPsImp::mConsensus
RCLConsensus mConsensus
Definition: NetworkOPs.cpp:756
-
ripple::NetworkOPsImp::unsubAccount
void unsubAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3651
-
ripple::NetworkOPsImp::getOwnerInfo
Json::Value getOwnerInfo(std::shared_ptr< ReadView const > lpLedger, AccountID const &account) override
Definition: NetworkOPs.cpp:1742
-
ripple::NetworkOPsImp::setNeedNetworkLedger
void setNeedNetworkLedger() override
Definition: NetworkOPs.cpp:907
-
ripple::NetworkOPsImp::setUNLBlocked
void setUNLBlocked() override
Definition: NetworkOPs.cpp:1857
-
ripple::NetworkOPsImp::pubConsensus
void pubConsensus(ConsensusPhase phase)
Definition: NetworkOPs.cpp:2365
-
ripple::NetworkOPsImp::transactionBatch
void transactionBatch()
Apply transactions in batches.
Definition: NetworkOPs.cpp:1460
-
ripple::NetworkOPsImp::apply
void apply(std::unique_lock< std::mutex > &batchLock)
Attempt to apply transactions and post-process based on the results.
Definition: NetworkOPs.cpp:1474
-
ripple::NetworkOPsImp::setAmendmentBlocked
void setAmendmentBlocked() override
Definition: NetworkOPs.cpp:1826
-
ripple::NetworkOPsImp::checkLastClosedLedger
bool checkLastClosedLedger(Overlay::PeerSequence const &, uint256 &networkClosed)
Definition: NetworkOPs.cpp:1870
-
ripple::NetworkOPsImp::processTransaction
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.
Definition: NetworkOPs.cpp:1302
-
ripple::NetworkOPsImp::processTransactionSet
void processTransactionSet(CanonicalTXSet const &set) override
Process a set of transactions synchronously, and ensuring that they are processed in one batch.
Definition: NetworkOPs.cpp:1397
-
ripple::NetworkOPsImp::SubTypes
SubTypes
Definition: NetworkOPs.cpp:772
-
ripple::NetworkOPsImp::sPeerStatus
@ sPeerStatus
Definition: NetworkOPs.cpp:779
-
ripple::NetworkOPsImp::sManifests
@ sManifests
Definition: NetworkOPs.cpp:774
-
ripple::NetworkOPsImp::sConsensusPhase
@ sConsensusPhase
Definition: NetworkOPs.cpp:780
-
ripple::NetworkOPsImp::sLedger
@ sLedger
Definition: NetworkOPs.cpp:773
-
ripple::NetworkOPsImp::sTransactions
@ sTransactions
Definition: NetworkOPs.cpp:776
-
ripple::NetworkOPsImp::sServer
@ sServer
Definition: NetworkOPs.cpp:775
-
ripple::NetworkOPsImp::sRTTransactions
@ sRTTransactions
Definition: NetworkOPs.cpp:777
-
ripple::NetworkOPsImp::sBookChanges
@ sBookChanges
Definition: NetworkOPs.cpp:781
-
ripple::NetworkOPsImp::sValidations
@ sValidations
Definition: NetworkOPs.cpp:778
-
ripple::NetworkOPsImp::sLastEntry
@ sLastEntry
Definition: NetworkOPs.cpp:782
-
ripple::NetworkOPsImp::clearUNLBlocked
void clearUNLBlocked() override
Definition: NetworkOPs.cpp:1864
-
ripple::NetworkOPsImp::heartbeatTimer_
boost::asio::steady_timer heartbeatTimer_
Definition: NetworkOPs.cpp:752
-
ripple::NetworkOPsImp::updateLocalTx
void updateLocalTx(ReadView const &view) override
Definition: NetworkOPs.cpp:3223
-
ripple::NetworkOPsImp::unsubManifests
bool unsubManifests(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4225
-
ripple::NetworkOPsImp::DispatchState
DispatchState
Synchronization states for transaction batches.
Definition: NetworkOPs.cpp:120
+
ripple::NetworkOPsImp::StateAccounting
State accounting records two attributes for each possible server state: 1) Amount of time spent in ea...
Definition: NetworkOPs.cpp:144
+
ripple::NetworkOPsImp::StateAccounting::mode
void mode(OperatingMode om)
Record state transition.
Definition: NetworkOPs.cpp:4794
+
ripple::NetworkOPsImp::StateAccounting::json
void json(Json::Value &obj) const
Output state counters in JSON format.
Definition: NetworkOPs.cpp:4815
+
ripple::NetworkOPsImp::StateAccounting::counters_
std::array< Counters, 5 > counters_
Definition: NetworkOPs.cpp:154
+
ripple::NetworkOPsImp::StateAccounting::initialSyncUs_
std::uint64_t initialSyncUs_
Definition: NetworkOPs.cpp:159
+
ripple::NetworkOPsImp::StateAccounting::getCounterData
CounterData getCounterData() const
Definition: NetworkOPs.cpp:195
+
ripple::NetworkOPsImp::StateAccounting::start_
std::chrono::steady_clock::time_point start_
Definition: NetworkOPs.cpp:156
+
ripple::NetworkOPsImp::StateAccounting::mutex_
std::mutex mutex_
Definition: NetworkOPs.cpp:155
+
ripple::NetworkOPsImp::StateAccounting::states_
static std::array< Json::StaticString const, 5 > const states_
Definition: NetworkOPs.cpp:160
+
ripple::NetworkOPsImp::StateAccounting::StateAccounting
StateAccounting()
Definition: NetworkOPs.cpp:163
+
ripple::NetworkOPsImp::StateAccounting::processStart_
std::chrono::steady_clock::time_point const processStart_
Definition: NetworkOPs.cpp:158
+
ripple::NetworkOPsImp::StateAccounting::mode_
OperatingMode mode_
Definition: NetworkOPs.cpp:153
+
ripple::NetworkOPsImp::TransactionStatus
Transaction with input flags and results to be applied in batches.
Definition: NetworkOPs.cpp:95
+
ripple::NetworkOPsImp::TransactionStatus::TransactionStatus
TransactionStatus(std::shared_ptr< Transaction > t, bool a, bool l, FailHard f)
Definition: NetworkOPs.cpp:104
+
ripple::NetworkOPsImp::TransactionStatus::admin
bool const admin
Definition: NetworkOPs.cpp:98
+
ripple::NetworkOPsImp::TransactionStatus::applied
bool applied
Definition: NetworkOPs.cpp:101
+
ripple::NetworkOPsImp::TransactionStatus::transaction
std::shared_ptr< Transaction > const transaction
Definition: NetworkOPs.cpp:97
+
ripple::NetworkOPsImp::TransactionStatus::failType
FailHard const failType
Definition: NetworkOPs.cpp:100
+
ripple::NetworkOPsImp::TransactionStatus::result
TER result
Definition: NetworkOPs.cpp:102
+
ripple::NetworkOPsImp::TransactionStatus::local
bool const local
Definition: NetworkOPs.cpp:99
+
ripple::NetworkOPsImp
Definition: NetworkOPs.cpp:89
+
ripple::NetworkOPsImp::processClusterTimer
void processClusterTimer()
Definition: NetworkOPs.cpp:1119
+
ripple::NetworkOPsImp::accountHistoryTxTimer_
boost::asio::steady_timer accountHistoryTxTimer_
Definition: NetworkOPs.cpp:755
+
ripple::NetworkOPsImp::pubProposedTransaction
void pubProposedTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result) override
Definition: NetworkOPs.cpp:3043
+
ripple::NetworkOPsImp::getOperatingMode
OperatingMode getOperatingMode() const override
Definition: NetworkOPs.cpp:890
+
ripple::NetworkOPsImp::strOperatingMode
std::string strOperatingMode(OperatingMode const mode, bool const admin) const override
Definition: NetworkOPs.cpp:1167
+
ripple::NetworkOPsImp::preProcessTransaction
bool preProcessTransaction(std::shared_ptr< Transaction > &transaction)
Definition: NetworkOPs.cpp:1250
+
ripple::NetworkOPsImp::mTransactions
std::vector< TransactionStatus > mTransactions
Definition: NetworkOPs.cpp:802
+
ripple::NetworkOPsImp::unsubBookChanges
bool unsubBookChanges(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4209
+
ripple::NetworkOPsImp::mMode
std::atomic< OperatingMode > mMode
Definition: NetworkOPs.cpp:745
+
ripple::NetworkOPsImp::setHeartbeatTimer
void setHeartbeatTimer()
Definition: NetworkOPs.cpp:993
+
ripple::NetworkOPsImp::getLedgerFetchInfo
Json::Value getLedgerFetchInfo() override
Definition: NetworkOPs.cpp:3037
+
ripple::NetworkOPsImp::isUNLBlocked
bool isUNLBlocked() override
Definition: NetworkOPs.cpp:1852
+
ripple::NetworkOPsImp::mConsensus
RCLConsensus mConsensus
Definition: NetworkOPs.cpp:757
+
ripple::NetworkOPsImp::unsubAccount
void unsubAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3653
+
ripple::NetworkOPsImp::getOwnerInfo
Json::Value getOwnerInfo(std::shared_ptr< ReadView const > lpLedger, AccountID const &account) override
Definition: NetworkOPs.cpp:1743
+
ripple::NetworkOPsImp::setNeedNetworkLedger
void setNeedNetworkLedger() override
Definition: NetworkOPs.cpp:908
+
ripple::NetworkOPsImp::setUNLBlocked
void setUNLBlocked() override
Definition: NetworkOPs.cpp:1858
+
ripple::NetworkOPsImp::pubConsensus
void pubConsensus(ConsensusPhase phase)
Definition: NetworkOPs.cpp:2366
+
ripple::NetworkOPsImp::transactionBatch
void transactionBatch()
Apply transactions in batches.
Definition: NetworkOPs.cpp:1461
+
ripple::NetworkOPsImp::apply
void apply(std::unique_lock< std::mutex > &batchLock)
Attempt to apply transactions and post-process based on the results.
Definition: NetworkOPs.cpp:1475
+
ripple::NetworkOPsImp::setAmendmentBlocked
void setAmendmentBlocked() override
Definition: NetworkOPs.cpp:1827
+
ripple::NetworkOPsImp::checkLastClosedLedger
bool checkLastClosedLedger(Overlay::PeerSequence const &, uint256 &networkClosed)
Definition: NetworkOPs.cpp:1871
+
ripple::NetworkOPsImp::processTransaction
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.
Definition: NetworkOPs.cpp:1303
+
ripple::NetworkOPsImp::processTransactionSet
void processTransactionSet(CanonicalTXSet const &set) override
Process a set of transactions synchronously, and ensuring that they are processed in one batch.
Definition: NetworkOPs.cpp:1398
+
ripple::NetworkOPsImp::SubTypes
SubTypes
Definition: NetworkOPs.cpp:773
+
ripple::NetworkOPsImp::sPeerStatus
@ sPeerStatus
Definition: NetworkOPs.cpp:780
+
ripple::NetworkOPsImp::sManifests
@ sManifests
Definition: NetworkOPs.cpp:775
+
ripple::NetworkOPsImp::sConsensusPhase
@ sConsensusPhase
Definition: NetworkOPs.cpp:781
+
ripple::NetworkOPsImp::sLedger
@ sLedger
Definition: NetworkOPs.cpp:774
+
ripple::NetworkOPsImp::sTransactions
@ sTransactions
Definition: NetworkOPs.cpp:777
+
ripple::NetworkOPsImp::sServer
@ sServer
Definition: NetworkOPs.cpp:776
+
ripple::NetworkOPsImp::sRTTransactions
@ sRTTransactions
Definition: NetworkOPs.cpp:778
+
ripple::NetworkOPsImp::sBookChanges
@ sBookChanges
Definition: NetworkOPs.cpp:782
+
ripple::NetworkOPsImp::sValidations
@ sValidations
Definition: NetworkOPs.cpp:779
+
ripple::NetworkOPsImp::sLastEntry
@ sLastEntry
Definition: NetworkOPs.cpp:783
+
ripple::NetworkOPsImp::clearUNLBlocked
void clearUNLBlocked() override
Definition: NetworkOPs.cpp:1865
+
ripple::NetworkOPsImp::heartbeatTimer_
boost::asio::steady_timer heartbeatTimer_
Definition: NetworkOPs.cpp:753
+
ripple::NetworkOPsImp::updateLocalTx
void updateLocalTx(ReadView const &view) override
Definition: NetworkOPs.cpp:3224
+
ripple::NetworkOPsImp::unsubManifests
bool unsubManifests(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4227
+
ripple::NetworkOPsImp::DispatchState
DispatchState
Synchronization states for transaction batches.
Definition: NetworkOPs.cpp:121
ripple::NetworkOPsImp::DispatchState::none
@ none
ripple::NetworkOPsImp::DispatchState::scheduled
@ scheduled
ripple::NetworkOPsImp::DispatchState::running
@ running
-
ripple::NetworkOPsImp::validatorPK_
std::optional< PublicKey > const validatorPK_
Definition: NetworkOPs.cpp:758
-
ripple::NetworkOPsImp::unsubTransactions
bool unsubTransactions(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4281
-
ripple::NetworkOPsImp::setClusterTimer
void setClusterTimer()
Definition: NetworkOPs.cpp:1006
-
ripple::NetworkOPsImp::clearAmendmentWarned
void clearAmendmentWarned() override
Definition: NetworkOPs.cpp:1845
-
ripple::NetworkOPsImp::getLocalTxCount
std::size_t getLocalTxCount() override
Definition: NetworkOPs.cpp:3228
-
ripple::NetworkOPsImp::m_localTX
std::unique_ptr< LocalTxs > m_localTX
Definition: NetworkOPs.cpp:740
-
ripple::NetworkOPsImp::subValidations
bool subValidations(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4307
-
ripple::NetworkOPsImp::subLedger
bool subLedger(InfoSub::ref ispListener, Json::Value &jvResult) override
Definition: NetworkOPs.cpp:4159
-
ripple::NetworkOPsImp::~NetworkOPsImp
~NetworkOPsImp() override
Definition: NetworkOPs.cpp:270
-
ripple::NetworkOPsImp::isAmendmentBlocked
bool isAmendmentBlocked() override
Definition: NetworkOPs.cpp:1820
-
ripple::NetworkOPsImp::unsubAccountHistoryInternal
void unsubAccountHistoryInternal(std::uint64_t seq, AccountID const &account, bool historyOnly) override
Definition: NetworkOPs.cpp:4088
-
ripple::NetworkOPsImp::mSubAccountHistory
SubAccountHistoryMapType mSubAccountHistory
Definition: NetworkOPs.cpp:770
-
ripple::NetworkOPsImp::getServerInfo
Json::Value getServerInfo(bool human, bool admin, bool counters) override
Definition: NetworkOPs.cpp:2625
-
ripple::NetworkOPsImp::addRpcSub
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::ref) override
Definition: NetworkOPs.cpp:4379
-
ripple::NetworkOPsImp::clusterTimer_
boost::asio::steady_timer clusterTimer_
Definition: NetworkOPs.cpp:753
-
ripple::NetworkOPsImp::isAmendmentWarned
bool isAmendmentWarned() override
Definition: NetworkOPs.cpp:1833
-
ripple::NetworkOPsImp::states_
static std::array< char const *, 5 > const states_
Definition: NetworkOPs.cpp:126
-
ripple::NetworkOPsImp::subServer
bool subServer(InfoSub::ref ispListener, Json::Value &jvResult, bool admin) override
Definition: NetworkOPs.cpp:4233
-
ripple::NetworkOPsImp::NetworkOPsImp
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)
Definition: NetworkOPs.cpp:226
-
ripple::NetworkOPsImp::unsubAccountInternal
void unsubAccountInternal(std::uint64_t seq, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3667
-
ripple::NetworkOPsImp::amendmentBlocked_
std::atomic< bool > amendmentBlocked_
Definition: NetworkOPs.cpp:747
-
ripple::NetworkOPsImp::m_journal
beast::Journal m_journal
Definition: NetworkOPs.cpp:738
-
ripple::NetworkOPsImp::mSubAccount
SubInfoMapType mSubAccount
Definition: NetworkOPs.cpp:765
-
ripple::NetworkOPsImp::validatorMasterPK_
std::optional< PublicKey > const validatorMasterPK_
Definition: NetworkOPs.cpp:759
-
ripple::NetworkOPsImp::unsubAccountHistory
void unsubAccountHistory(InfoSub::ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
Definition: NetworkOPs.cpp:4077
-
ripple::NetworkOPsImp::pendingValidations_
std::set< uint256 > pendingValidations_
Definition: NetworkOPs.cpp:805
-
ripple::NetworkOPsImp::beginConsensus
bool beginConsensus(uint256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
Definition: NetworkOPs.cpp:2030
-
ripple::NetworkOPsImp::doTransactionAsync
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
Definition: NetworkOPs.cpp:1321
-
ripple::NetworkOPsImp::setAccountHistoryJobTimer
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
Definition: NetworkOPs.cpp:1022
-
ripple::NetworkOPsImp::unsubValidations
bool unsubValidations(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4323
-
ripple::NetworkOPsImp::endConsensus
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
Definition: NetworkOPs.cpp:2150
-
ripple::NetworkOPsImp::m_standalone
bool const m_standalone
Definition: NetworkOPs.cpp:792
-
ripple::NetworkOPsImp::waitHandlerCounter_
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
Definition: NetworkOPs.cpp:751
-
ripple::NetworkOPsImp::pubLedger
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
Definition: NetworkOPs.cpp:3081
-
ripple::NetworkOPsImp::addAccountHistoryJob
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
Definition: NetworkOPs.cpp:3695
-
ripple::NetworkOPsImp::doTransactionSync
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...
Definition: NetworkOPs.cpp:1346
-
ripple::NetworkOPsImp::setTimer
void setTimer(boost::asio::steady_timer &timer, std::chrono::milliseconds const &expiry_time, std::function< void()> onExpire, std::function< void()> onError)
Definition: NetworkOPs.cpp:960
-
ripple::NetworkOPsImp::pubServer
void pubServer()
Definition: NetworkOPs.cpp:2297
-
ripple::NetworkOPsImp::mStreamMaps
std::array< SubMapType, SubTypes::sLastEntry > mStreamMaps
Definition: NetworkOPs.cpp:785
-
ripple::NetworkOPsImp::unsubPeerStatus
bool unsubPeerStatus(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4341
-
ripple::NetworkOPsImp::pubValidation
void pubValidation(std::shared_ptr< STValidation > const &val) override
Definition: NetworkOPs.cpp:2392
-
ripple::NetworkOPsImp::minPeerCount_
std::size_t const minPeerCount_
Definition: NetworkOPs.cpp:795
-
ripple::NetworkOPsImp::unlBlocked_
std::atomic< bool > unlBlocked_
Definition: NetworkOPs.cpp:749
-
ripple::NetworkOPsImp::subBook
bool subBook(InfoSub::ref ispListener, Book const &) override
Definition: NetworkOPs.cpp:4119
-
ripple::NetworkOPsImp::acceptLedger
std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay) override
Accepts the current transaction tree, return the new ledger's sequence.
Definition: NetworkOPs.cpp:4138
-
ripple::NetworkOPsImp::stateAccounting
void stateAccounting(Json::Value &obj) override
Definition: NetworkOPs.cpp:4316
-
ripple::NetworkOPsImp::submitTransaction
void submitTransaction(std::shared_ptr< STTx const > const &) override
Definition: NetworkOPs.cpp:1186
-
ripple::NetworkOPsImp::unsubRTTransactions
bool unsubRTTransactions(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4299
-
ripple::NetworkOPsImp::m_statsMutex
std::mutex m_statsMutex
Definition: NetworkOPs.cpp:860
-
ripple::NetworkOPsImp::getConsensusInfo
Json::Value getConsensusInfo() override
Definition: NetworkOPs.cpp:2619
-
ripple::NetworkOPsImp::m_job_queue
JobQueue & m_job_queue
Definition: NetworkOPs.cpp:789
-
ripple::NetworkOPsImp::mSubLock
std::recursive_mutex mSubLock
Definition: NetworkOPs.cpp:742
-
ripple::NetworkOPsImp::needNetworkLedger_
std::atomic< bool > needNetworkLedger_
Definition: NetworkOPs.cpp:746
-
ripple::NetworkOPsImp::recvValidation
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
Definition: NetworkOPs.cpp:2560
-
ripple::NetworkOPsImp::switchLastClosedLedger
void switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
Definition: NetworkOPs.cpp:1976
-
ripple::NetworkOPsImp::accounting_
StateAccounting accounting_
Definition: NetworkOPs.cpp:803
-
ripple::NetworkOPsImp::reportConsensusStateChange
void reportConsensusStateChange(ConsensusPhase phase)
Definition: NetworkOPs.cpp:3214
-
ripple::NetworkOPsImp::subConsensus
bool subConsensus(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4349
-
ripple::NetworkOPsImp::isNeedNetworkLedger
bool isNeedNetworkLedger() override
Definition: NetworkOPs.cpp:919
-
ripple::NetworkOPsImp::collect_metrics
void collect_metrics()
Definition: NetworkOPs.cpp:4754
-
ripple::NetworkOPsImp::setAmendmentWarned
void setAmendmentWarned() override
Definition: NetworkOPs.cpp:1839
-
ripple::NetworkOPsImp::processTrustedProposal
bool processTrustedProposal(RCLCxPeerPos proposal) override
Definition: NetworkOPs.cpp:2105
-
ripple::NetworkOPsImp::doTransactionSyncBatch
void doTransactionSyncBatch(std::unique_lock< std::mutex > &lock, std::function< bool(std::unique_lock< std::mutex > const &)> retryCallback)
Definition: NetworkOPs.cpp:1367
-
ripple::NetworkOPsImp::subPeerStatus
bool subPeerStatus(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4331
-
ripple::NetworkOPsImp::mapComplete
void mapComplete(std::shared_ptr< SHAMap > const &map, bool fromAcquire) override
Definition: NetworkOPs.cpp:2131
-
ripple::NetworkOPsImp::tryRemoveRpcSub
bool tryRemoveRpcSub(std::string const &strUrl) override
Definition: NetworkOPs.cpp:4389
-
ripple::NetworkOPsImp::pubAccountTransaction
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
Definition: NetworkOPs.cpp:3401
-
ripple::NetworkOPsImp::m_ledgerMaster
LedgerMaster & m_ledgerMaster
Definition: NetworkOPs.cpp:763
-
ripple::NetworkOPsImp::clearLedgerFetch
void clearLedgerFetch() override
Definition: NetworkOPs.cpp:3030
-
ripple::NetworkOPsImp::isBlocked
bool isBlocked() override
Definition: NetworkOPs.cpp:1814
-
ripple::NetworkOPsImp::consensusViewChange
void consensusViewChange() override
Definition: NetworkOPs.cpp:2209
-
ripple::NetworkOPsImp::setStateTimer
void setStateTimer() override
Called to initially start our timers.
Definition: NetworkOPs.cpp:950
-
ripple::NetworkOPsImp::subManifests
bool subManifests(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4215
-
ripple::NetworkOPsImp::pubValidatedTransaction
void pubValidatedTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
Definition: NetworkOPs.cpp:3345
-
ripple::NetworkOPsImp::subAccount
void subAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3614
-
ripple::NetworkOPsImp::unsubServer
bool unsubServer(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4263
-
ripple::NetworkOPsImp::transJson
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)
Definition: NetworkOPs.cpp:3236
-
ripple::NetworkOPsImp::mLastFeeSummary
ServerFeeSummary mLastFeeSummary
Definition: NetworkOPs.cpp:787
-
ripple::NetworkOPsImp::pubPeerStatus
void pubPeerStatus(std::function< Json::Value(void)> const &) override
Definition: NetworkOPs.cpp:2502
-
ripple::NetworkOPsImp::setStandAlone
void setStandAlone() override
Definition: NetworkOPs.cpp:901
-
ripple::NetworkOPsImp::subRTTransactions
bool subRTTransactions(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4289
-
ripple::NetworkOPsImp::pubProposedAccountTransaction
void pubProposedAccountTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result)
Definition: NetworkOPs.cpp:3535
-
ripple::NetworkOPsImp::m_stats
Stats m_stats
Definition: NetworkOPs.cpp:861
-
ripple::NetworkOPsImp::mCond
std::condition_variable mCond
Definition: NetworkOPs.cpp:798
-
ripple::NetworkOPsImp::setMode
void setMode(OperatingMode om) override
Definition: NetworkOPs.cpp:2531
-
ripple::NetworkOPsImp::stop
void stop() override
Definition: NetworkOPs.cpp:587
-
ripple::NetworkOPsImp::getBookPage
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
Definition: NetworkOPs.cpp:4414
-
ripple::NetworkOPsImp::clearNeedNetworkLedger
void clearNeedNetworkLedger() override
Definition: NetworkOPs.cpp:913
-
ripple::NetworkOPsImp::mDispatchState
DispatchState mDispatchState
Definition: NetworkOPs.cpp:800
-
ripple::NetworkOPsImp::subBookChanges
bool subBookChanges(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4189
-
ripple::NetworkOPsImp::mSubRTAccount
SubInfoMapType mSubRTAccount
Definition: NetworkOPs.cpp:766
-
ripple::NetworkOPsImp::mMutex
std::mutex mMutex
Definition: NetworkOPs.cpp:799
-
ripple::NetworkOPsImp::reportFeeChange
void reportFeeChange() override
Definition: NetworkOPs.cpp:3196
-
ripple::NetworkOPsImp::processHeartbeatTimer
void processHeartbeatTimer()
Definition: NetworkOPs.cpp:1035
-
ripple::NetworkOPsImp::unsubBook
bool unsubBook(std::uint64_t uListener, Book const &) override
Definition: NetworkOPs.cpp:4129
-
ripple::NetworkOPsImp::subAccountHistoryStart
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
Definition: NetworkOPs.cpp:3985
-
ripple::NetworkOPsImp::isFull
bool isFull() override
Definition: NetworkOPs.cpp:925
-
ripple::NetworkOPsImp::subAccountHistory
error_code_i subAccountHistory(InfoSub::ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
Definition: NetworkOPs.cpp:4031
-
ripple::NetworkOPsImp::validationsMutex_
std::mutex validationsMutex_
Definition: NetworkOPs.cpp:806
-
ripple::NetworkOPsImp::app_
Application & app_
Definition: NetworkOPs.cpp:737
-
ripple::NetworkOPsImp::pubManifest
void pubManifest(Manifest const &) override
Definition: NetworkOPs.cpp:2218
-
ripple::NetworkOPsImp::mLastConsensusPhase
ConsensusPhase mLastConsensusPhase
Definition: NetworkOPs.cpp:761
-
ripple::NetworkOPsImp::subTransactions
bool subTransactions(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4271
-
ripple::NetworkOPsImp::mRpcSubMap
subRpcMapType mRpcSubMap
Definition: NetworkOPs.cpp:768
-
ripple::NetworkOPsImp::amendmentWarned_
std::atomic< bool > amendmentWarned_
Definition: NetworkOPs.cpp:748
-
ripple::NetworkOPsImp::findRpcSub
InfoSub::pointer findRpcSub(std::string const &strUrl) override
Definition: NetworkOPs.cpp:4366
-
ripple::NetworkOPsImp::unsubLedger
bool unsubLedger(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4199
-
ripple::NetworkOPsImp::getHostId
std::string getHostId(bool forAdmin)
Definition: NetworkOPs.cpp:931
-
ripple::NetworkOPsImp::unsubConsensus
bool unsubConsensus(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4359
+
ripple::NetworkOPsImp::validatorPK_
std::optional< PublicKey > const validatorPK_
Definition: NetworkOPs.cpp:759
+
ripple::NetworkOPsImp::unsubTransactions
bool unsubTransactions(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4283
+
ripple::NetworkOPsImp::setClusterTimer
void setClusterTimer()
Definition: NetworkOPs.cpp:1007
+
ripple::NetworkOPsImp::clearAmendmentWarned
void clearAmendmentWarned() override
Definition: NetworkOPs.cpp:1846
+
ripple::NetworkOPsImp::getLocalTxCount
std::size_t getLocalTxCount() override
Definition: NetworkOPs.cpp:3229
+
ripple::NetworkOPsImp::m_localTX
std::unique_ptr< LocalTxs > m_localTX
Definition: NetworkOPs.cpp:741
+
ripple::NetworkOPsImp::subValidations
bool subValidations(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4309
+
ripple::NetworkOPsImp::subLedger
bool subLedger(InfoSub::ref ispListener, Json::Value &jvResult) override
Definition: NetworkOPs.cpp:4161
+
ripple::NetworkOPsImp::~NetworkOPsImp
~NetworkOPsImp() override
Definition: NetworkOPs.cpp:271
+
ripple::NetworkOPsImp::isAmendmentBlocked
bool isAmendmentBlocked() override
Definition: NetworkOPs.cpp:1821
+
ripple::NetworkOPsImp::unsubAccountHistoryInternal
void unsubAccountHistoryInternal(std::uint64_t seq, AccountID const &account, bool historyOnly) override
Definition: NetworkOPs.cpp:4090
+
ripple::NetworkOPsImp::mSubAccountHistory
SubAccountHistoryMapType mSubAccountHistory
Definition: NetworkOPs.cpp:771
+
ripple::NetworkOPsImp::getServerInfo
Json::Value getServerInfo(bool human, bool admin, bool counters) override
Definition: NetworkOPs.cpp:2626
+
ripple::NetworkOPsImp::addRpcSub
InfoSub::pointer addRpcSub(std::string const &strUrl, InfoSub::ref) override
Definition: NetworkOPs.cpp:4381
+
ripple::NetworkOPsImp::clusterTimer_
boost::asio::steady_timer clusterTimer_
Definition: NetworkOPs.cpp:754
+
ripple::NetworkOPsImp::isAmendmentWarned
bool isAmendmentWarned() override
Definition: NetworkOPs.cpp:1834
+
ripple::NetworkOPsImp::states_
static std::array< char const *, 5 > const states_
Definition: NetworkOPs.cpp:127
+
ripple::NetworkOPsImp::subServer
bool subServer(InfoSub::ref ispListener, Json::Value &jvResult, bool admin) override
Definition: NetworkOPs.cpp:4235
+
ripple::NetworkOPsImp::NetworkOPsImp
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)
Definition: NetworkOPs.cpp:227
+
ripple::NetworkOPsImp::unsubAccountInternal
void unsubAccountInternal(std::uint64_t seq, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3669
+
ripple::NetworkOPsImp::amendmentBlocked_
std::atomic< bool > amendmentBlocked_
Definition: NetworkOPs.cpp:748
+
ripple::NetworkOPsImp::m_journal
beast::Journal m_journal
Definition: NetworkOPs.cpp:739
+
ripple::NetworkOPsImp::mSubAccount
SubInfoMapType mSubAccount
Definition: NetworkOPs.cpp:766
+
ripple::NetworkOPsImp::validatorMasterPK_
std::optional< PublicKey > const validatorMasterPK_
Definition: NetworkOPs.cpp:760
+
ripple::NetworkOPsImp::unsubAccountHistory
void unsubAccountHistory(InfoSub::ref ispListener, AccountID const &account, bool historyOnly) override
unsubscribe an account's transactions
Definition: NetworkOPs.cpp:4079
+
ripple::NetworkOPsImp::pendingValidations_
std::set< uint256 > pendingValidations_
Definition: NetworkOPs.cpp:806
+
ripple::NetworkOPsImp::beginConsensus
bool beginConsensus(uint256 const &networkClosed, std::unique_ptr< std::stringstream > const &clog) override
Definition: NetworkOPs.cpp:2031
+
ripple::NetworkOPsImp::doTransactionAsync
void doTransactionAsync(std::shared_ptr< Transaction > transaction, bool bUnlimited, FailHard failtype)
For transactions not submitted by a locally connected client, fire and forget.
Definition: NetworkOPs.cpp:1322
+
ripple::NetworkOPsImp::setAccountHistoryJobTimer
void setAccountHistoryJobTimer(SubAccountHistoryInfoWeak subInfo)
Definition: NetworkOPs.cpp:1023
+
ripple::NetworkOPsImp::unsubValidations
bool unsubValidations(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4325
+
ripple::NetworkOPsImp::endConsensus
void endConsensus(std::unique_ptr< std::stringstream > const &clog) override
Definition: NetworkOPs.cpp:2151
+
ripple::NetworkOPsImp::m_standalone
bool const m_standalone
Definition: NetworkOPs.cpp:793
+
ripple::NetworkOPsImp::waitHandlerCounter_
ClosureCounter< void, boost::system::error_code const & > waitHandlerCounter_
Definition: NetworkOPs.cpp:752
+
ripple::NetworkOPsImp::pubLedger
void pubLedger(std::shared_ptr< ReadView const > const &lpAccepted) override
Definition: NetworkOPs.cpp:3082
+
ripple::NetworkOPsImp::addAccountHistoryJob
void addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo)
Definition: NetworkOPs.cpp:3697
+
ripple::NetworkOPsImp::doTransactionSync
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...
Definition: NetworkOPs.cpp:1347
+
ripple::NetworkOPsImp::setTimer
void setTimer(boost::asio::steady_timer &timer, std::chrono::milliseconds const &expiry_time, std::function< void()> onExpire, std::function< void()> onError)
Definition: NetworkOPs.cpp:961
+
ripple::NetworkOPsImp::pubServer
void pubServer()
Definition: NetworkOPs.cpp:2298
+
ripple::NetworkOPsImp::mStreamMaps
std::array< SubMapType, SubTypes::sLastEntry > mStreamMaps
Definition: NetworkOPs.cpp:786
+
ripple::NetworkOPsImp::unsubPeerStatus
bool unsubPeerStatus(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4343
+
ripple::NetworkOPsImp::pubValidation
void pubValidation(std::shared_ptr< STValidation > const &val) override
Definition: NetworkOPs.cpp:2393
+
ripple::NetworkOPsImp::minPeerCount_
std::size_t const minPeerCount_
Definition: NetworkOPs.cpp:796
+
ripple::NetworkOPsImp::unlBlocked_
std::atomic< bool > unlBlocked_
Definition: NetworkOPs.cpp:750
+
ripple::NetworkOPsImp::subBook
bool subBook(InfoSub::ref ispListener, Book const &) override
Definition: NetworkOPs.cpp:4121
+
ripple::NetworkOPsImp::acceptLedger
std::uint32_t acceptLedger(std::optional< std::chrono::milliseconds > consensusDelay) override
Accepts the current transaction tree, return the new ledger's sequence.
Definition: NetworkOPs.cpp:4140
+
ripple::NetworkOPsImp::stateAccounting
void stateAccounting(Json::Value &obj) override
Definition: NetworkOPs.cpp:4318
+
ripple::NetworkOPsImp::submitTransaction
void submitTransaction(std::shared_ptr< STTx const > const &) override
Definition: NetworkOPs.cpp:1187
+
ripple::NetworkOPsImp::unsubRTTransactions
bool unsubRTTransactions(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4301
+
ripple::NetworkOPsImp::m_statsMutex
std::mutex m_statsMutex
Definition: NetworkOPs.cpp:861
+
ripple::NetworkOPsImp::getConsensusInfo
Json::Value getConsensusInfo() override
Definition: NetworkOPs.cpp:2620
+
ripple::NetworkOPsImp::m_job_queue
JobQueue & m_job_queue
Definition: NetworkOPs.cpp:790
+
ripple::NetworkOPsImp::mSubLock
std::recursive_mutex mSubLock
Definition: NetworkOPs.cpp:743
+
ripple::NetworkOPsImp::needNetworkLedger_
std::atomic< bool > needNetworkLedger_
Definition: NetworkOPs.cpp:747
+
ripple::NetworkOPsImp::recvValidation
bool recvValidation(std::shared_ptr< STValidation > const &val, std::string const &source) override
Definition: NetworkOPs.cpp:2561
+
ripple::NetworkOPsImp::switchLastClosedLedger
void switchLastClosedLedger(std::shared_ptr< Ledger const > const &newLCL)
Definition: NetworkOPs.cpp:1977
+
ripple::NetworkOPsImp::accounting_
StateAccounting accounting_
Definition: NetworkOPs.cpp:804
+
ripple::NetworkOPsImp::reportConsensusStateChange
void reportConsensusStateChange(ConsensusPhase phase)
Definition: NetworkOPs.cpp:3215
+
ripple::NetworkOPsImp::subConsensus
bool subConsensus(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4351
+
ripple::NetworkOPsImp::isNeedNetworkLedger
bool isNeedNetworkLedger() override
Definition: NetworkOPs.cpp:920
+
ripple::NetworkOPsImp::collect_metrics
void collect_metrics()
Definition: NetworkOPs.cpp:4756
+
ripple::NetworkOPsImp::setAmendmentWarned
void setAmendmentWarned() override
Definition: NetworkOPs.cpp:1840
+
ripple::NetworkOPsImp::processTrustedProposal
bool processTrustedProposal(RCLCxPeerPos proposal) override
Definition: NetworkOPs.cpp:2106
+
ripple::NetworkOPsImp::doTransactionSyncBatch
void doTransactionSyncBatch(std::unique_lock< std::mutex > &lock, std::function< bool(std::unique_lock< std::mutex > const &)> retryCallback)
Definition: NetworkOPs.cpp:1368
+
ripple::NetworkOPsImp::subPeerStatus
bool subPeerStatus(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4333
+
ripple::NetworkOPsImp::mapComplete
void mapComplete(std::shared_ptr< SHAMap > const &map, bool fromAcquire) override
Definition: NetworkOPs.cpp:2132
+
ripple::NetworkOPsImp::tryRemoveRpcSub
bool tryRemoveRpcSub(std::string const &strUrl) override
Definition: NetworkOPs.cpp:4391
+
ripple::NetworkOPsImp::pubAccountTransaction
void pubAccountTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
Definition: NetworkOPs.cpp:3403
+
ripple::NetworkOPsImp::m_ledgerMaster
LedgerMaster & m_ledgerMaster
Definition: NetworkOPs.cpp:764
+
ripple::NetworkOPsImp::clearLedgerFetch
void clearLedgerFetch() override
Definition: NetworkOPs.cpp:3031
+
ripple::NetworkOPsImp::isBlocked
bool isBlocked() override
Definition: NetworkOPs.cpp:1815
+
ripple::NetworkOPsImp::consensusViewChange
void consensusViewChange() override
Definition: NetworkOPs.cpp:2210
+
ripple::NetworkOPsImp::setStateTimer
void setStateTimer() override
Called to initially start our timers.
Definition: NetworkOPs.cpp:951
+
ripple::NetworkOPsImp::subManifests
bool subManifests(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4217
+
ripple::NetworkOPsImp::pubValidatedTransaction
void pubValidatedTransaction(std::shared_ptr< ReadView const > const &ledger, AcceptedLedgerTx const &transaction, bool last)
Definition: NetworkOPs.cpp:3347
+
ripple::NetworkOPsImp::subAccount
void subAccount(InfoSub::ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool rt) override
Definition: NetworkOPs.cpp:3616
+
ripple::NetworkOPsImp::unsubServer
bool unsubServer(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4265
+
ripple::NetworkOPsImp::transJson
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)
Definition: NetworkOPs.cpp:3237
+
ripple::NetworkOPsImp::mLastFeeSummary
ServerFeeSummary mLastFeeSummary
Definition: NetworkOPs.cpp:788
+
ripple::NetworkOPsImp::pubPeerStatus
void pubPeerStatus(std::function< Json::Value(void)> const &) override
Definition: NetworkOPs.cpp:2503
+
ripple::NetworkOPsImp::setStandAlone
void setStandAlone() override
Definition: NetworkOPs.cpp:902
+
ripple::NetworkOPsImp::subRTTransactions
bool subRTTransactions(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4291
+
ripple::NetworkOPsImp::pubProposedAccountTransaction
void pubProposedAccountTransaction(std::shared_ptr< ReadView const > const &ledger, std::shared_ptr< STTx const > const &transaction, TER result)
Definition: NetworkOPs.cpp:3537
+
ripple::NetworkOPsImp::m_stats
Stats m_stats
Definition: NetworkOPs.cpp:862
+
ripple::NetworkOPsImp::mCond
std::condition_variable mCond
Definition: NetworkOPs.cpp:799
+
ripple::NetworkOPsImp::setMode
void setMode(OperatingMode om) override
Definition: NetworkOPs.cpp:2532
+
ripple::NetworkOPsImp::stop
void stop() override
Definition: NetworkOPs.cpp:588
+
ripple::NetworkOPsImp::getBookPage
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
Definition: NetworkOPs.cpp:4416
+
ripple::NetworkOPsImp::clearNeedNetworkLedger
void clearNeedNetworkLedger() override
Definition: NetworkOPs.cpp:914
+
ripple::NetworkOPsImp::mDispatchState
DispatchState mDispatchState
Definition: NetworkOPs.cpp:801
+
ripple::NetworkOPsImp::subBookChanges
bool subBookChanges(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4191
+
ripple::NetworkOPsImp::mSubRTAccount
SubInfoMapType mSubRTAccount
Definition: NetworkOPs.cpp:767
+
ripple::NetworkOPsImp::mMutex
std::mutex mMutex
Definition: NetworkOPs.cpp:800
+
ripple::NetworkOPsImp::reportFeeChange
void reportFeeChange() override
Definition: NetworkOPs.cpp:3197
+
ripple::NetworkOPsImp::processHeartbeatTimer
void processHeartbeatTimer()
Definition: NetworkOPs.cpp:1036
+
ripple::NetworkOPsImp::unsubBook
bool unsubBook(std::uint64_t uListener, Book const &) override
Definition: NetworkOPs.cpp:4131
+
ripple::NetworkOPsImp::subAccountHistoryStart
void subAccountHistoryStart(std::shared_ptr< ReadView const > const &ledger, SubAccountHistoryInfoWeak &subInfo)
Definition: NetworkOPs.cpp:3987
+
ripple::NetworkOPsImp::isFull
bool isFull() override
Definition: NetworkOPs.cpp:926
+
ripple::NetworkOPsImp::subAccountHistory
error_code_i subAccountHistory(InfoSub::ref ispListener, AccountID const &account) override
subscribe an account's new transactions and retrieve the account's historical transactions
Definition: NetworkOPs.cpp:4033
+
ripple::NetworkOPsImp::validationsMutex_
std::mutex validationsMutex_
Definition: NetworkOPs.cpp:807
+
ripple::NetworkOPsImp::app_
Application & app_
Definition: NetworkOPs.cpp:738
+
ripple::NetworkOPsImp::pubManifest
void pubManifest(Manifest const &) override
Definition: NetworkOPs.cpp:2219
+
ripple::NetworkOPsImp::mLastConsensusPhase
ConsensusPhase mLastConsensusPhase
Definition: NetworkOPs.cpp:762
+
ripple::NetworkOPsImp::subTransactions
bool subTransactions(InfoSub::ref ispListener) override
Definition: NetworkOPs.cpp:4273
+
ripple::NetworkOPsImp::mRpcSubMap
subRpcMapType mRpcSubMap
Definition: NetworkOPs.cpp:769
+
ripple::NetworkOPsImp::amendmentWarned_
std::atomic< bool > amendmentWarned_
Definition: NetworkOPs.cpp:749
+
ripple::NetworkOPsImp::findRpcSub
InfoSub::pointer findRpcSub(std::string const &strUrl) override
Definition: NetworkOPs.cpp:4368
+
ripple::NetworkOPsImp::unsubLedger
bool unsubLedger(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4201
+
ripple::NetworkOPsImp::getHostId
std::string getHostId(bool forAdmin)
Definition: NetworkOPs.cpp:932
+
ripple::NetworkOPsImp::unsubConsensus
bool unsubConsensus(std::uint64_t uListener) override
Definition: NetworkOPs.cpp:4361
ripple::NetworkOPs
Provides server functionality for clients.
Definition: NetworkOPs.h:89
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:93
ripple::NetworkOPs::FailHard::no
@ no
@@ -5249,6 +5251,7 @@ $(function() {
ripple::BuildInfo::getVersionString
std::string const & getVersionString()
Server version.
Definition: BuildInfo.cpp:68
ripple::RPC::encodeCTID
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Definition: CTID.h:43
ripple::RPC::computeBookChanges
Json::Value computeBookChanges(std::shared_ptr< L const > const &lpAccepted)
Definition: BookChanges.h:47
+
ripple::RPC::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:34
ripple::RPC::insertMPTokenIssuanceID
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition: MPTokenIssuanceID.cpp:64
ripple::RPC::insertDeliveredAmount
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.
Definition: DeliveredAmount.cpp:129
ripple::Resource::feeMediumBurdenRPC
Charge const feeMediumBurdenRPC
@@ -5282,7 +5285,7 @@ $(function() {
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition: View.cpp:761
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:1013
ripple::handleNewValidation
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.
Definition: RCLValidations.cpp:165
-
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4838
+
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4840
ripple::warnRPC_EXPIRED_VALIDATOR_LIST
@ warnRPC_EXPIRED_VALIDATOR_LIST
Definition: ErrorCodes.h:170
ripple::warnRPC_UNSUPPORTED_MAJORITY
@ warnRPC_UNSUPPORTED_MAJORITY
Definition: ErrorCodes.h:168
ripple::warnRPC_AMENDMENT_BLOCKED
@ warnRPC_AMENDMENT_BLOCKED
Definition: ErrorCodes.h:169
@@ -5302,7 +5305,7 @@ $(function() {
ripple::tefPAST_SEQ
@ tefPAST_SEQ
Definition: TER.h:175
ripple::isTefFailure
bool isTefFailure(TER x) noexcept
Definition: TER.h:662
ripple::ConsensusPhase
ConsensusPhase
Phases of consensus for a single ledger round.
Definition: ConsensusTypes.h:105
-
ripple::stateNames
static std::array< char const *, 5 > const stateNames
Definition: NetworkOPs.cpp:870
+
ripple::stateNames
static std::array< char const *, 5 > const stateNames
Definition: NetworkOPs.cpp:871
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::cdirNext
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.
Definition: View.cpp:158
ripple::KeyType::secp256k1
@ secp256k1
@@ -5344,13 +5347,13 @@ $(function() {
ripple::tfInnerBatchTxn
constexpr std::uint32_t tfInnerBatchTxn
Definition: TxFlags.h:61
ripple::parityRate
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
ripple::isGlobalFrozen
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:184
-
ripple::trunc32
static std::uint32_t trunc32(std::uint64_t v)
Definition: NetworkOPs.cpp:2289
+
ripple::trunc32
static std::uint32_t trunc32(std::uint64_t v)
Definition: NetworkOPs.cpp:2290
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:111
ripple::temBAD_SIGNATURE
@ temBAD_SIGNATURE
Definition: TER.h:105
ripple::BypassAccept
BypassAccept
Definition: RCLValidations.h:37
ripple::BypassAccept::no
@ no
ripple::BypassAccept::yes
@ yes
-
ripple::genesisAccountId
static auto const genesisAccountId
Definition: NetworkOPs.cpp:883
+
ripple::genesisAccountId
static auto const genesisAccountId
Definition: NetworkOPs.cpp:884
std
STL namespace.
std::chrono::steady_clock::now
T now(T... args)
optional
@@ -5379,51 +5382,51 @@ $(function() {
ripple::Manifest::signingKey
std::optional< PublicKey > signingKey
The ephemeral key associated with this manifest.
Definition: Manifest.h:92
ripple::Manifest::getMasterSignature
Blob getMasterSignature() const
Returns manifest master key signature.
Definition: Manifest.cpp:255
ripple::Manifest::masterKey
PublicKey masterKey
The master key associated with this manifest.
Definition: Manifest.h:86
-
ripple::NetworkOPsImp::ServerFeeSummary
Server fees published on server subscription.
Definition: NetworkOPs.cpp:203
-
ripple::NetworkOPsImp::ServerFeeSummary::operator!=
bool operator!=(ServerFeeSummary const &b) const
Definition: NetworkOPs.cpp:2268
+
ripple::NetworkOPsImp::ServerFeeSummary
Server fees published on server subscription.
Definition: NetworkOPs.cpp:204
+
ripple::NetworkOPsImp::ServerFeeSummary::operator!=
bool operator!=(ServerFeeSummary const &b) const
Definition: NetworkOPs.cpp:2269
ripple::NetworkOPsImp::ServerFeeSummary::ServerFeeSummary
ServerFeeSummary()=default
-
ripple::NetworkOPsImp::ServerFeeSummary::baseFee
XRPAmount baseFee
Definition: NetworkOPs.cpp:221
-
ripple::NetworkOPsImp::ServerFeeSummary::em
std::optional< TxQ::Metrics > em
Definition: NetworkOPs.cpp:222
-
ripple::NetworkOPsImp::ServerFeeSummary::loadFactorServer
std::uint32_t loadFactorServer
Definition: NetworkOPs.cpp:219
-
ripple::NetworkOPsImp::ServerFeeSummary::operator==
bool operator==(ServerFeeSummary const &b) const
Definition: NetworkOPs.cpp:214
-
ripple::NetworkOPsImp::ServerFeeSummary::loadBaseServer
std::uint32_t loadBaseServer
Definition: NetworkOPs.cpp:220
-
ripple::NetworkOPsImp::StateAccounting::CounterData
Definition: NetworkOPs.cpp:186
-
ripple::NetworkOPsImp::StateAccounting::CounterData::start
decltype(start_) start
Definition: NetworkOPs.cpp:189
-
ripple::NetworkOPsImp::StateAccounting::CounterData::initialSyncUs
decltype(initialSyncUs_) initialSyncUs
Definition: NetworkOPs.cpp:190
-
ripple::NetworkOPsImp::StateAccounting::CounterData::mode
decltype(mode_) mode
Definition: NetworkOPs.cpp:188
-
ripple::NetworkOPsImp::StateAccounting::CounterData::counters
decltype(counters_) counters
Definition: NetworkOPs.cpp:187
-
ripple::NetworkOPsImp::StateAccounting::Counters
Definition: NetworkOPs.cpp:145
+
ripple::NetworkOPsImp::ServerFeeSummary::baseFee
XRPAmount baseFee
Definition: NetworkOPs.cpp:222
+
ripple::NetworkOPsImp::ServerFeeSummary::em
std::optional< TxQ::Metrics > em
Definition: NetworkOPs.cpp:223
+
ripple::NetworkOPsImp::ServerFeeSummary::loadFactorServer
std::uint32_t loadFactorServer
Definition: NetworkOPs.cpp:220
+
ripple::NetworkOPsImp::ServerFeeSummary::operator==
bool operator==(ServerFeeSummary const &b) const
Definition: NetworkOPs.cpp:215
+
ripple::NetworkOPsImp::ServerFeeSummary::loadBaseServer
std::uint32_t loadBaseServer
Definition: NetworkOPs.cpp:221
+
ripple::NetworkOPsImp::StateAccounting::CounterData
Definition: NetworkOPs.cpp:187
+
ripple::NetworkOPsImp::StateAccounting::CounterData::start
decltype(start_) start
Definition: NetworkOPs.cpp:190
+
ripple::NetworkOPsImp::StateAccounting::CounterData::initialSyncUs
decltype(initialSyncUs_) initialSyncUs
Definition: NetworkOPs.cpp:191
+
ripple::NetworkOPsImp::StateAccounting::CounterData::mode
decltype(mode_) mode
Definition: NetworkOPs.cpp:189
+
ripple::NetworkOPsImp::StateAccounting::CounterData::counters
decltype(counters_) counters
Definition: NetworkOPs.cpp:188
+
ripple::NetworkOPsImp::StateAccounting::Counters
Definition: NetworkOPs.cpp:146
ripple::NetworkOPsImp::StateAccounting::Counters::Counters
Counters()=default
-
ripple::NetworkOPsImp::StateAccounting::Counters::transitions
std::uint64_t transitions
Definition: NetworkOPs.cpp:148
-
ripple::NetworkOPsImp::StateAccounting::Counters::dur
std::chrono::microseconds dur
Definition: NetworkOPs.cpp:149
-
ripple::NetworkOPsImp::Stats
Definition: NetworkOPs.cpp:810
-
ripple::NetworkOPsImp::Stats::full_transitions
beast::insight::Gauge full_transitions
Definition: NetworkOPs.cpp:857
-
ripple::NetworkOPsImp::Stats::Stats
Stats(Handler const &handler, beast::insight::Collector::ptr const &collector)
Definition: NetworkOPs.cpp:812
-
ripple::NetworkOPsImp::Stats::hook
beast::insight::Hook hook
Definition: NetworkOPs.cpp:846
-
ripple::NetworkOPsImp::Stats::connected_duration
beast::insight::Gauge connected_duration
Definition: NetworkOPs.cpp:848
-
ripple::NetworkOPsImp::Stats::tracking_duration
beast::insight::Gauge tracking_duration
Definition: NetworkOPs.cpp:850
-
ripple::NetworkOPsImp::Stats::connected_transitions
beast::insight::Gauge connected_transitions
Definition: NetworkOPs.cpp:854
-
ripple::NetworkOPsImp::Stats::disconnected_transitions
beast::insight::Gauge disconnected_transitions
Definition: NetworkOPs.cpp:853
-
ripple::NetworkOPsImp::Stats::syncing_duration
beast::insight::Gauge syncing_duration
Definition: NetworkOPs.cpp:849
-
ripple::NetworkOPsImp::Stats::tracking_transitions
beast::insight::Gauge tracking_transitions
Definition: NetworkOPs.cpp:856
-
ripple::NetworkOPsImp::Stats::full_duration
beast::insight::Gauge full_duration
Definition: NetworkOPs.cpp:851
-
ripple::NetworkOPsImp::Stats::disconnected_duration
beast::insight::Gauge disconnected_duration
Definition: NetworkOPs.cpp:847
-
ripple::NetworkOPsImp::Stats::syncing_transitions
beast::insight::Gauge syncing_transitions
Definition: NetworkOPs.cpp:855
-
ripple::NetworkOPsImp::SubAccountHistoryIndex
Definition: NetworkOPs.cpp:689
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::historyLastLedgerSeq_
std::uint32_t historyLastLedgerSeq_
Definition: NetworkOPs.cpp:696
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::separationLedgerSeq_
std::uint32_t separationLedgerSeq_
Definition: NetworkOPs.cpp:694
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::accountId_
AccountID const accountId_
Definition: NetworkOPs.cpp:690
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::forwardTxIndex_
std::uint32_t forwardTxIndex_
Definition: NetworkOPs.cpp:692
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::stopHistorical_
std::atomic< bool > stopHistorical_
Definition: NetworkOPs.cpp:699
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::historyTxIndex_
std::int32_t historyTxIndex_
Definition: NetworkOPs.cpp:697
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::SubAccountHistoryIndex
SubAccountHistoryIndex(AccountID const &accountId)
Definition: NetworkOPs.cpp:701
-
ripple::NetworkOPsImp::SubAccountHistoryIndex::haveHistorical_
bool haveHistorical_
Definition: NetworkOPs.cpp:698
-
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak
Definition: NetworkOPs.cpp:718
-
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak::index_
std::shared_ptr< SubAccountHistoryIndex > index_
Definition: NetworkOPs.cpp:720
-
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak::sinkWptr_
InfoSub::wptr sinkWptr_
Definition: NetworkOPs.cpp:719
-
ripple::NetworkOPsImp::SubAccountHistoryInfo
Definition: NetworkOPs.cpp:713
-
ripple::NetworkOPsImp::SubAccountHistoryInfo::index_
std::shared_ptr< SubAccountHistoryIndex > index_
Definition: NetworkOPs.cpp:715
-
ripple::NetworkOPsImp::SubAccountHistoryInfo::sink_
InfoSub::pointer sink_
Definition: NetworkOPs.cpp:714
+
ripple::NetworkOPsImp::StateAccounting::Counters::transitions
std::uint64_t transitions
Definition: NetworkOPs.cpp:149
+
ripple::NetworkOPsImp::StateAccounting::Counters::dur
std::chrono::microseconds dur
Definition: NetworkOPs.cpp:150
+
ripple::NetworkOPsImp::Stats
Definition: NetworkOPs.cpp:811
+
ripple::NetworkOPsImp::Stats::full_transitions
beast::insight::Gauge full_transitions
Definition: NetworkOPs.cpp:858
+
ripple::NetworkOPsImp::Stats::Stats
Stats(Handler const &handler, beast::insight::Collector::ptr const &collector)
Definition: NetworkOPs.cpp:813
+
ripple::NetworkOPsImp::Stats::hook
beast::insight::Hook hook
Definition: NetworkOPs.cpp:847
+
ripple::NetworkOPsImp::Stats::connected_duration
beast::insight::Gauge connected_duration
Definition: NetworkOPs.cpp:849
+
ripple::NetworkOPsImp::Stats::tracking_duration
beast::insight::Gauge tracking_duration
Definition: NetworkOPs.cpp:851
+
ripple::NetworkOPsImp::Stats::connected_transitions
beast::insight::Gauge connected_transitions
Definition: NetworkOPs.cpp:855
+
ripple::NetworkOPsImp::Stats::disconnected_transitions
beast::insight::Gauge disconnected_transitions
Definition: NetworkOPs.cpp:854
+
ripple::NetworkOPsImp::Stats::syncing_duration
beast::insight::Gauge syncing_duration
Definition: NetworkOPs.cpp:850
+
ripple::NetworkOPsImp::Stats::tracking_transitions
beast::insight::Gauge tracking_transitions
Definition: NetworkOPs.cpp:857
+
ripple::NetworkOPsImp::Stats::full_duration
beast::insight::Gauge full_duration
Definition: NetworkOPs.cpp:852
+
ripple::NetworkOPsImp::Stats::disconnected_duration
beast::insight::Gauge disconnected_duration
Definition: NetworkOPs.cpp:848
+
ripple::NetworkOPsImp::Stats::syncing_transitions
beast::insight::Gauge syncing_transitions
Definition: NetworkOPs.cpp:856
+
ripple::NetworkOPsImp::SubAccountHistoryIndex
Definition: NetworkOPs.cpp:690
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::historyLastLedgerSeq_
std::uint32_t historyLastLedgerSeq_
Definition: NetworkOPs.cpp:697
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::separationLedgerSeq_
std::uint32_t separationLedgerSeq_
Definition: NetworkOPs.cpp:695
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::accountId_
AccountID const accountId_
Definition: NetworkOPs.cpp:691
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::forwardTxIndex_
std::uint32_t forwardTxIndex_
Definition: NetworkOPs.cpp:693
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::stopHistorical_
std::atomic< bool > stopHistorical_
Definition: NetworkOPs.cpp:700
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::historyTxIndex_
std::int32_t historyTxIndex_
Definition: NetworkOPs.cpp:698
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::SubAccountHistoryIndex
SubAccountHistoryIndex(AccountID const &accountId)
Definition: NetworkOPs.cpp:702
+
ripple::NetworkOPsImp::SubAccountHistoryIndex::haveHistorical_
bool haveHistorical_
Definition: NetworkOPs.cpp:699
+
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak
Definition: NetworkOPs.cpp:719
+
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak::index_
std::shared_ptr< SubAccountHistoryIndex > index_
Definition: NetworkOPs.cpp:721
+
ripple::NetworkOPsImp::SubAccountHistoryInfoWeak::sinkWptr_
InfoSub::wptr sinkWptr_
Definition: NetworkOPs.cpp:720
+
ripple::NetworkOPsImp::SubAccountHistoryInfo
Definition: NetworkOPs.cpp:714
+
ripple::NetworkOPsImp::SubAccountHistoryInfo::index_
std::shared_ptr< SubAccountHistoryIndex > index_
Definition: NetworkOPs.cpp:716
+
ripple::NetworkOPsImp::SubAccountHistoryInfo::sink_
InfoSub::pointer sink_
Definition: NetworkOPs.cpp:715
ripple::Rate
Represents a transfer rate.
Definition: Rate.h:40
ripple::RelationalDatabase::AccountTxPageOptions
Definition: RelationalDatabase.h:76
ripple::Resource::Gossip
Data format for exchanging consumption information across peers.
Definition: Gossip.h:30
diff --git a/NetworkOPs_8h_source.html b/NetworkOPs_8h_source.html index 301b8d029a..2bf5728044 100644 --- a/NetworkOPs_8h_source.html +++ b/NetworkOPs_8h_source.html @@ -400,7 +400,7 @@ $(function() {
std::uint32_t
memory
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
-
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4838
+
ripple::make_NetworkOPs
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)
Definition: NetworkOPs.cpp:4840
ripple::OperatingMode
OperatingMode
Specifies the mode under which the server believes it's operating.
Definition: NetworkOPs.h:68
ripple::OperatingMode::TRACKING
@ TRACKING
convinced we agree with the network
ripple::OperatingMode::DISCONNECTED
@ DISCONNECTED
not ready to process requests
diff --git a/Subscribe__test_8cpp_source.html b/Subscribe__test_8cpp_source.html index 85d14f8821..59d4eae637 100644 --- a/Subscribe__test_8cpp_source.html +++ b/Subscribe__test_8cpp_source.html @@ -1431,31 +1431,252 @@ $(function() {
1355 }
1356
1357 void
-
1358 run() override
-
1359 {
-
1360 using namespace test::jtx;
-
1361 FeatureBitset const all{supported_amendments()};
-
1362 FeatureBitset const xrpFees{featureXRPFees};
-
1363
-
1364 testServer();
-
1365 testLedger();
-
1366 testTransactions_APIv1();
-
1367 testTransactions_APIv2();
-
1368 testManifests();
-
1369 testValidations(all - xrpFees);
-
1370 testValidations(all);
-
1371 testSubErrors(true);
-
1372 testSubErrors(false);
-
1373 testSubByUrl();
-
1374 testHistoryTxStream();
-
1375 testSubBookChanges();
-
1376 }
-
1377};
-
1378
-
1379BEAST_DEFINE_TESTSUITE(Subscribe, app, ripple);
-
1380
-
1381} // namespace test
-
1382} // namespace ripple
+
1358 testNFToken(FeatureBitset features)
+
1359 {
+
1360 // `nftoken_id` is added for `transaction` stream in the `subscribe`
+
1361 // response for NFTokenMint and NFTokenAcceptOffer.
+
1362 //
+
1363 // `nftoken_ids` is added for `transaction` stream in the `subscribe`
+
1364 // response for NFTokenCancelOffer
+
1365 //
+
1366 // `offer_id` is added for `transaction` stream in the `subscribe`
+
1367 // response for NFTokenCreateOffer
+
1368 //
+
1369 // The values of these fields are dependent on the NFTokenID/OfferID
+
1370 // changed in its corresponding transaction. We want to validate each
+
1371 // response to make sure the synethic fields hold the right values.
+
1372
+
1373 testcase("Test synthetic fields from Subscribe response");
+
1374
+
1375 using namespace test::jtx;
+
1376 using namespace std::chrono_literals;
+
1377
+
1378 Account const alice{"alice"};
+
1379 Account const bob{"bob"};
+
1380 Account const broker{"broker"};
+
1381
+
1382 Env env{*this, features};
+
1383 env.fund(XRP(10000), alice, bob, broker);
+
1384 env.close();
+
1385
+
1386 auto wsc = test::makeWSClient(env.app().config());
+
1387 Json::Value stream;
+
1388 stream[jss::streams] = Json::arrayValue;
+
1389 stream[jss::streams].append("transactions");
+
1390 auto jv = wsc->invoke("subscribe", stream);
+
1391
+
1392 // Verify `nftoken_id` value equals to the NFTokenID that was
+
1393 // changed in the most recent NFTokenMint or NFTokenAcceptOffer
+
1394 // transaction
+
1395 auto verifyNFTokenID = [&](uint256 const& actualNftID) {
+
1396 BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
1397 uint256 nftID;
+
1398 BEAST_EXPECT(
+
1399 nftID.parseHex(jv[jss::meta][jss::nftoken_id].asString()));
+
1400 return nftID == actualNftID;
+
1401 }));
+
1402 };
+
1403
+
1404 // Verify `nftoken_ids` value equals to the NFTokenIDs that were
+
1405 // changed in the most recent NFTokenCancelOffer transaction
+
1406 auto verifyNFTokenIDsInCancelOffer =
+
1407 [&](std::vector<uint256> actualNftIDs) {
+
1408 BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
1409 std::vector<uint256> metaIDs;
+
1410 std::transform(
+
1411 jv[jss::meta][jss::nftoken_ids].begin(),
+
1412 jv[jss::meta][jss::nftoken_ids].end(),
+
1413 std::back_inserter(metaIDs),
+
1414 [this](Json::Value id) {
+
1415 uint256 nftID;
+
1416 BEAST_EXPECT(nftID.parseHex(id.asString()));
+
1417 return nftID;
+
1418 });
+
1419 // Sort both array to prepare for comparison
+
1420 std::sort(metaIDs.begin(), metaIDs.end());
+
1421 std::sort(actualNftIDs.begin(), actualNftIDs.end());
+
1422
+
1423 // Make sure the expect number of NFTs is correct
+
1424 BEAST_EXPECT(metaIDs.size() == actualNftIDs.size());
+
1425
+
1426 // Check the value of NFT ID in the meta with the
+
1427 // actual values
+
1428 for (size_t i = 0; i < metaIDs.size(); ++i)
+
1429 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
+
1430 return true;
+
1431 }));
+
1432 };
+
1433
+
1434 // Verify `offer_id` value equals to the offerID that was
+
1435 // changed in the most recent NFTokenCreateOffer tx
+
1436 auto verifyNFTokenOfferID = [&](uint256 const& offerID) {
+
1437 BEAST_EXPECT(wsc->findMsg(5s, [&](auto const& jv) {
+
1438 uint256 metaOfferID;
+
1439 BEAST_EXPECT(metaOfferID.parseHex(
+
1440 jv[jss::meta][jss::offer_id].asString()));
+
1441 return metaOfferID == offerID;
+
1442 }));
+
1443 };
+
1444
+
1445 // Check new fields in tx meta when for all NFTtransactions
+
1446 {
+
1447 // Alice mints 2 NFTs
+
1448 // Verify the NFTokenIDs are correct in the NFTokenMint tx meta
+
1449 uint256 const nftId1{
+
1450 token::getNextID(env, alice, 0u, tfTransferable)};
+
1451 env(token::mint(alice, 0u), txflags(tfTransferable));
+
1452 env.close();
+
1453 verifyNFTokenID(nftId1);
+
1454
+
1455 uint256 const nftId2{
+
1456 token::getNextID(env, alice, 0u, tfTransferable)};
+
1457 env(token::mint(alice, 0u), txflags(tfTransferable));
+
1458 env.close();
+
1459 verifyNFTokenID(nftId2);
+
1460
+
1461 // Alice creates one sell offer for each NFT
+
1462 // Verify the offer indexes are correct in the NFTokenCreateOffer tx
+
1463 // meta
+
1464 uint256 const aliceOfferIndex1 =
+
1465 keylet::nftoffer(alice, env.seq(alice)).key;
+
1466 env(token::createOffer(alice, nftId1, drops(1)),
+
1467 txflags(tfSellNFToken));
+
1468 env.close();
+
1469 verifyNFTokenOfferID(aliceOfferIndex1);
+
1470
+
1471 uint256 const aliceOfferIndex2 =
+
1472 keylet::nftoffer(alice, env.seq(alice)).key;
+
1473 env(token::createOffer(alice, nftId2, drops(1)),
+
1474 txflags(tfSellNFToken));
+
1475 env.close();
+
1476 verifyNFTokenOfferID(aliceOfferIndex2);
+
1477
+
1478 // Alice cancels two offers she created
+
1479 // Verify the NFTokenIDs are correct in the NFTokenCancelOffer tx
+
1480 // meta
+
1481 env(token::cancelOffer(
+
1482 alice, {aliceOfferIndex1, aliceOfferIndex2}));
+
1483 env.close();
+
1484 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
+
1485
+
1486 // Bobs creates a buy offer for nftId1
+
1487 // Verify the offer id is correct in the NFTokenCreateOffer tx meta
+
1488 auto const bobBuyOfferIndex =
+
1489 keylet::nftoffer(bob, env.seq(bob)).key;
+
1490 env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice));
+
1491 env.close();
+
1492 verifyNFTokenOfferID(bobBuyOfferIndex);
+
1493
+
1494 // Alice accepts bob's buy offer
+
1495 // Verify the NFTokenID is correct in the NFTokenAcceptOffer tx meta
+
1496 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
+
1497 env.close();
+
1498 verifyNFTokenID(nftId1);
+
1499 }
+
1500
+
1501 // Check `nftoken_ids` in brokered mode
+
1502 {
+
1503 // Alice mints a NFT
+
1504 uint256 const nftId{
+
1505 token::getNextID(env, alice, 0u, tfTransferable)};
+
1506 env(token::mint(alice, 0u), txflags(tfTransferable));
+
1507 env.close();
+
1508 verifyNFTokenID(nftId);
+
1509
+
1510 // Alice creates sell offer and set broker as destination
+
1511 uint256 const offerAliceToBroker =
+
1512 keylet::nftoffer(alice, env.seq(alice)).key;
+
1513 env(token::createOffer(alice, nftId, drops(1)),
+
1514 token::destination(broker),
+
1515 txflags(tfSellNFToken));
+
1516 env.close();
+
1517 verifyNFTokenOfferID(offerAliceToBroker);
+
1518
+
1519 // Bob creates buy offer
+
1520 uint256 const offerBobToBroker =
+
1521 keylet::nftoffer(bob, env.seq(bob)).key;
+
1522 env(token::createOffer(bob, nftId, drops(1)), token::owner(alice));
+
1523 env.close();
+
1524 verifyNFTokenOfferID(offerBobToBroker);
+
1525
+
1526 // Check NFTokenID meta for NFTokenAcceptOffer in brokered mode
+
1527 env(token::brokerOffers(
+
1528 broker, offerBobToBroker, offerAliceToBroker));
+
1529 env.close();
+
1530 verifyNFTokenID(nftId);
+
1531 }
+
1532
+
1533 // Check if there are no duplicate nft id in Cancel transactions where
+
1534 // multiple offers are cancelled for the same NFT
+
1535 {
+
1536 // Alice mints a NFT
+
1537 uint256 const nftId{
+
1538 token::getNextID(env, alice, 0u, tfTransferable)};
+
1539 env(token::mint(alice, 0u), txflags(tfTransferable));
+
1540 env.close();
+
1541 verifyNFTokenID(nftId);
+
1542
+
1543 // Alice creates 2 sell offers for the same NFT
+
1544 uint256 const aliceOfferIndex1 =
+
1545 keylet::nftoffer(alice, env.seq(alice)).key;
+
1546 env(token::createOffer(alice, nftId, drops(1)),
+
1547 txflags(tfSellNFToken));
+
1548 env.close();
+
1549 verifyNFTokenOfferID(aliceOfferIndex1);
+
1550
+
1551 uint256 const aliceOfferIndex2 =
+
1552 keylet::nftoffer(alice, env.seq(alice)).key;
+
1553 env(token::createOffer(alice, nftId, drops(1)),
+
1554 txflags(tfSellNFToken));
+
1555 env.close();
+
1556 verifyNFTokenOfferID(aliceOfferIndex2);
+
1557
+
1558 // Make sure the metadata only has 1 nft id, since both offers are
+
1559 // for the same nft
+
1560 env(token::cancelOffer(
+
1561 alice, {aliceOfferIndex1, aliceOfferIndex2}));
+
1562 env.close();
+
1563 verifyNFTokenIDsInCancelOffer({nftId});
+
1564 }
+
1565
+
1566 if (features[featureNFTokenMintOffer])
+
1567 {
+
1568 uint256 const aliceMintWithOfferIndex1 =
+
1569 keylet::nftoffer(alice, env.seq(alice)).key;
+
1570 env(token::mint(alice), token::amount(XRP(0)));
+
1571 env.close();
+
1572 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
+
1573 }
+
1574 }
+
1575
+
1576 void
+
1577 run() override
+
1578 {
+
1579 using namespace test::jtx;
+
1580 FeatureBitset const all{supported_amendments()};
+
1581 FeatureBitset const xrpFees{featureXRPFees};
+
1582
+
1583 testServer();
+
1584 testLedger();
+
1585 testTransactions_APIv1();
+
1586 testTransactions_APIv2();
+
1587 testManifests();
+
1588 testValidations(all - xrpFees);
+
1589 testValidations(all);
+
1590 testSubErrors(true);
+
1591 testSubErrors(false);
+
1592 testSubByUrl();
+
1593 testHistoryTxStream();
+
1594 testSubBookChanges();
+
1595 testNFToken(all);
+
1596 testNFToken(all - featureNFTokenMintOffer);
+
1597 }
+
1598};
+
1599
+
1600BEAST_DEFINE_TESTSUITE(Subscribe, app, ripple);
+
1601
+
1602} // namespace test
+
1603} // namespace ripple
std::array
std::string
Json::Value
Represents a JSON value.
Definition: json_value.h:150
@@ -1470,16 +1691,18 @@ $(function() {
ripple::LoadFeeTrack::raiseLocalFee
bool raiseLocalFee()
Definition: LoadFeeTrack.cpp:33
ripple::LoadManager::stop
void stop()
Definition: LoadManager.cpp:85
ripple::NetworkOPs::reportFeeChange
virtual void reportFeeChange()=0
+
ripple::base_uint< 256 >
ripple::test::Subscribe_test
Definition: Subscribe_test.cpp:38
ripple::test::Subscribe_test::testSubBookChanges
void testSubBookChanges()
Definition: Subscribe_test.cpp:1304
ripple::test::Subscribe_test::testLedger
void testLedger()
Definition: Subscribe_test.cpp:112
ripple::test::Subscribe_test::testTransactions_APIv2
void testTransactions_APIv2()
Definition: Subscribe_test.cpp:316
-
ripple::test::Subscribe_test::run
void run() override
Runs the suite.
Definition: Subscribe_test.cpp:1358
+
ripple::test::Subscribe_test::run
void run() override
Runs the suite.
Definition: Subscribe_test.cpp:1577
ripple::test::Subscribe_test::testHistoryTxStream
void testHistoryTxStream()
Definition: Subscribe_test.cpp:845
ripple::test::Subscribe_test::testTransactions_APIv1
void testTransactions_APIv1()
Definition: Subscribe_test.cpp:170
ripple::test::Subscribe_test::testManifests
void testManifests()
Definition: Subscribe_test.cpp:398
ripple::test::Subscribe_test::testServer
void testServer()
Definition: Subscribe_test.cpp:41
ripple::test::Subscribe_test::testSubByUrl
void testSubByUrl()
Definition: Subscribe_test.cpp:552
+
ripple::test::Subscribe_test::testNFToken
void testNFToken(FeatureBitset features)
Definition: Subscribe_test.cpp:1358
ripple::test::Subscribe_test::testValidations
void testValidations(FeatureBitset features)
Definition: Subscribe_test.cpp:435
ripple::test::Subscribe_test::testSubErrors
void testSubErrors(bool subscribe)
Definition: Subscribe_test.cpp:580
ripple::test::WSClient
Definition: WSClient.h:35
@@ -1521,8 +1744,16 @@ $(function() {
Json::intValue
@ intValue
signed integer value
Definition: json_value.h:40
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
Json::uintValue
@ uintValue
unsigned integer value
Definition: json_value.h:41
+
ripple::keylet::nftoffer
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:427
+
ripple::test::jtx::token::getNextID
uint256 getNextID(jtx::Env const &env, jtx::Account const &issuer, std::uint32_t nfTokenTaxon, std::uint16_t flags, std::uint16_t xferFee)
Get the next NFTokenID that will be issued.
Definition: token.cpp:68
+
ripple::test::jtx::token::createOffer
Json::Value createOffer(jtx::Account const &account, uint256 const &nftokenID, STAmount const &amount)
Create an NFTokenOffer.
Definition: token.cpp:113
+
ripple::test::jtx::token::acceptBuyOffer
Json::Value acceptBuyOffer(jtx::Account const &account, uint256 const &offerIndex)
Accept an NFToken buy offer.
Definition: token.cpp:183
+
ripple::test::jtx::token::mint
Json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
Definition: token.cpp:34
+
ripple::test::jtx::token::cancelOffer
Json::Value cancelOffer(jtx::Account const &account, std::initializer_list< uint256 > const &nftokenOffers)
Cancel NFTokenOffers.
Definition: token.cpp:161
+
ripple::test::jtx::token::brokerOffers
Json::Value brokerOffers(jtx::Account const &account, uint256 const &buyOfferIndex, uint256 const &sellOfferIndex)
Broker two NFToken offers.
Definition: token.cpp:203
ripple::test::jtx::validator
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
Definition: envconfig.cpp:113
ripple::test::jtx::autofill
static autofill_t const autofill
Definition: tags.h:42
+
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: src/test/jtx/amount.h:297
ripple::test::jtx::no_admin
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition: envconfig.cpp:76
ripple::test::jtx::pay
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:30
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
@@ -1533,6 +1764,8 @@ $(function() {
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
ripple::TokenType::NodePublic
@ NodePublic
+
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:558
+
ripple::tfSellNFToken
constexpr std::uint32_t const tfSellNFToken
Definition: TxFlags.h:194
ripple::tfHybrid
constexpr std::uint32_t tfHybrid
Definition: TxFlags.h:102
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:331
ripple::generateSecretKey
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:309
@@ -1542,10 +1775,13 @@ $(function() {
ripple::vfFullyCanonicalSig
constexpr std::uint32_t vfFullyCanonicalSig
Definition: STValidation.h:44
ripple::to_string
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
ripple::vfFullValidation
constexpr std::uint32_t vfFullValidation
Definition: STValidation.h:41
+
ripple::tfTransferable
constexpr std::uint32_t const tfTransferable
Definition: TxFlags.h:140
std::optional
std::pair
std::size_t
+
std::sort
T sort(T... args)
ripple::JsonOptions::include_date
@ include_date
Definition: STBase.h:45
+
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:34
std::to_string
T to_string(T... args)
tuple
diff --git a/Tx_8cpp_source.html b/Tx_8cpp_source.html index 28549998c3..1d71192068 100644 --- a/Tx_8cpp_source.html +++ b/Tx_8cpp_source.html @@ -348,7 +348,7 @@ $(function() {
270 response[jss::meta] = meta->getJson(JsonOptions::none);
271 insertDeliveredAmount(
272 response[jss::meta], context, result.txn, *meta);
-
273 insertNFTSyntheticInJson(response, sttx, *meta);
+
273 RPC::insertNFTSyntheticInJson(response, sttx, *meta);
274 RPC::insertMPTokenIssuanceID(response[jss::meta], sttx, *meta);
275 }
276 }
@@ -454,6 +454,7 @@ $(function() {
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
ripple::RPC::encodeCTID
std::optional< std::string > encodeCTID(uint32_t ledgerSeq, uint32_t txnIndex, uint32_t networkID) noexcept
Definition: CTID.h:43
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:188
+
ripple::RPC::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:34
ripple::RPC::insertMPTokenIssuanceID
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
Definition: MPTokenIssuanceID.cpp:64
ripple::RPC::insertDeliverMax
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition: DeliverMax.cpp:28
ripple::RPC::decodeCTID
std::optional< std::tuple< uint32_t, uint16_t, uint16_t > > decodeCTID(T const ctid) noexcept
Definition: CTID.h:60
@@ -467,7 +468,6 @@ $(function() {
ripple::rpcNOT_ENABLED
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:59
ripple::rpcWRONG_NETWORK
@ rpcWRONG_NETWORK
Definition: ErrorCodes.h:50
ripple::rpcDB_DESERIALIZATION
@ rpcDB_DESERIALIZATION
Definition: ErrorCodes.h:134
-
ripple::insertNFTSyntheticInJson
void insertNFTSyntheticInJson(Json::Value &, std::shared_ptr< STTx const > const &, TxMeta const &)
Adds common synthetic fields to transaction-related JSON responses.
Definition: NFTSyntheticSerializer.cpp:33
ripple::doTxHelp
std::pair< TxResult, RPC::Status > doTxHelp(RPC::Context &context, TxArgs args)
Definition: Tx.cpp:75
ripple::doTxJson
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:286
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
diff --git a/classripple_1_1NetworkOPsImp.html b/classripple_1_1NetworkOPsImp.html index 3b29549e59..d9c0656bce 100644 --- a/classripple_1_1NetworkOPsImp.html +++ b/classripple_1_1NetworkOPsImp.html @@ -521,7 +521,7 @@ Static Private Attributes

Detailed Description

-

Definition at line 87 of file NetworkOPs.cpp.

+

Definition at line 88 of file NetworkOPs.cpp.

Member Typedef Documentation

◆ SubMapType

@@ -543,7 +543,7 @@ Static Private Attributes
-

Definition at line 676 of file NetworkOPs.cpp.

+

Definition at line 677 of file NetworkOPs.cpp.

@@ -567,7 +567,7 @@ Static Private Attributes
-

Definition at line 677 of file NetworkOPs.cpp.

+

Definition at line 678 of file NetworkOPs.cpp.

@@ -591,7 +591,7 @@ Static Private Attributes
-

Definition at line 678 of file NetworkOPs.cpp.

+

Definition at line 679 of file NetworkOPs.cpp.

@@ -615,7 +615,7 @@ Static Private Attributes
-

Definition at line 722 of file NetworkOPs.cpp.

+

Definition at line 723 of file NetworkOPs.cpp.

@@ -671,7 +671,7 @@ Static Private Attributes running  -

Definition at line 120 of file NetworkOPs.cpp.

+

Definition at line 121 of file NetworkOPs.cpp.

@@ -707,7 +707,7 @@ Static Private Attributes sLastEntry  -

Definition at line 772 of file NetworkOPs.cpp.

+

Definition at line 773 of file NetworkOPs.cpp.

@@ -820,7 +820,7 @@ Static Private Attributes
-

Definition at line 226 of file NetworkOPs.cpp.

+

Definition at line 227 of file NetworkOPs.cpp.

@@ -847,7 +847,7 @@ Static Private Attributes
-

Definition at line 270 of file NetworkOPs.cpp.

+

Definition at line 271 of file NetworkOPs.cpp.

@@ -877,7 +877,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 889 of file NetworkOPs.cpp.

+

Definition at line 890 of file NetworkOPs.cpp.

@@ -917,7 +917,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1166 of file NetworkOPs.cpp.

+

Definition at line 1167 of file NetworkOPs.cpp.

@@ -947,7 +947,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 895 of file NetworkOPs.cpp.

+

Definition at line 896 of file NetworkOPs.cpp.

@@ -977,7 +977,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1186 of file NetworkOPs.cpp.

+

Definition at line 1187 of file NetworkOPs.cpp.

@@ -1041,7 +1041,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1302 of file NetworkOPs.cpp.

+

Definition at line 1303 of file NetworkOPs.cpp.

@@ -1079,7 +1079,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1397 of file NetworkOPs.cpp.

+

Definition at line 1398 of file NetworkOPs.cpp.

@@ -1125,7 +1125,7 @@ Static Private Attributes -

Definition at line 1346 of file NetworkOPs.cpp.

+

Definition at line 1347 of file NetworkOPs.cpp.

@@ -1172,7 +1172,7 @@ Static Private Attributes -

Definition at line 1321 of file NetworkOPs.cpp.

+

Definition at line 1322 of file NetworkOPs.cpp.

@@ -1200,7 +1200,7 @@ Static Private Attributes
-

Definition at line 1249 of file NetworkOPs.cpp.

+

Definition at line 1250 of file NetworkOPs.cpp.

@@ -1238,7 +1238,7 @@ Static Private Attributes
-

Definition at line 1367 of file NetworkOPs.cpp.

+

Definition at line 1368 of file NetworkOPs.cpp.

@@ -1260,7 +1260,7 @@ Static Private Attributes

Apply transactions in batches.

Continue until none are queued.

-

Definition at line 1460 of file NetworkOPs.cpp.

+

Definition at line 1461 of file NetworkOPs.cpp.

@@ -1288,7 +1288,7 @@ Static Private Attributes -

Definition at line 1474 of file NetworkOPs.cpp.

+

Definition at line 1475 of file NetworkOPs.cpp.

@@ -1328,7 +1328,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1742 of file NetworkOPs.cpp.

+

Definition at line 1743 of file NetworkOPs.cpp.

@@ -1398,7 +1398,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 4414 of file NetworkOPs.cpp.

+

Definition at line 4416 of file NetworkOPs.cpp.

@@ -1428,7 +1428,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2105 of file NetworkOPs.cpp.

+

Definition at line 2106 of file NetworkOPs.cpp.

@@ -1468,7 +1468,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2560 of file NetworkOPs.cpp.

+

Definition at line 2561 of file NetworkOPs.cpp.

@@ -1508,7 +1508,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2131 of file NetworkOPs.cpp.

+

Definition at line 2132 of file NetworkOPs.cpp.

@@ -1536,7 +1536,7 @@ Static Private Attributes
-

Definition at line 1976 of file NetworkOPs.cpp.

+

Definition at line 1977 of file NetworkOPs.cpp.

@@ -1574,7 +1574,7 @@ Static Private Attributes
-

Definition at line 1870 of file NetworkOPs.cpp.

+

Definition at line 1871 of file NetworkOPs.cpp.

@@ -1614,7 +1614,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2030 of file NetworkOPs.cpp.

+

Definition at line 2031 of file NetworkOPs.cpp.

@@ -1644,7 +1644,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2150 of file NetworkOPs.cpp.

+

Definition at line 2151 of file NetworkOPs.cpp.

@@ -1673,7 +1673,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 901 of file NetworkOPs.cpp.

+

Definition at line 902 of file NetworkOPs.cpp.

@@ -1705,7 +1705,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 950 of file NetworkOPs.cpp.

+

Definition at line 951 of file NetworkOPs.cpp.

@@ -1734,7 +1734,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 907 of file NetworkOPs.cpp.

+

Definition at line 908 of file NetworkOPs.cpp.

@@ -1763,7 +1763,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 913 of file NetworkOPs.cpp.

+

Definition at line 914 of file NetworkOPs.cpp.

@@ -1792,7 +1792,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 919 of file NetworkOPs.cpp.

+

Definition at line 920 of file NetworkOPs.cpp.

@@ -1821,7 +1821,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 925 of file NetworkOPs.cpp.

+

Definition at line 926 of file NetworkOPs.cpp.

@@ -1851,7 +1851,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2531 of file NetworkOPs.cpp.

+

Definition at line 2532 of file NetworkOPs.cpp.

@@ -1880,7 +1880,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1814 of file NetworkOPs.cpp.

+

Definition at line 1815 of file NetworkOPs.cpp.

@@ -1909,7 +1909,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1820 of file NetworkOPs.cpp.

+

Definition at line 1821 of file NetworkOPs.cpp.

@@ -1938,7 +1938,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1826 of file NetworkOPs.cpp.

+

Definition at line 1827 of file NetworkOPs.cpp.

@@ -1967,7 +1967,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1833 of file NetworkOPs.cpp.

+

Definition at line 1834 of file NetworkOPs.cpp.

@@ -1996,7 +1996,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1839 of file NetworkOPs.cpp.

+

Definition at line 1840 of file NetworkOPs.cpp.

@@ -2025,7 +2025,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1845 of file NetworkOPs.cpp.

+

Definition at line 1846 of file NetworkOPs.cpp.

@@ -2054,7 +2054,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1851 of file NetworkOPs.cpp.

+

Definition at line 1852 of file NetworkOPs.cpp.

@@ -2083,7 +2083,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1857 of file NetworkOPs.cpp.

+

Definition at line 1858 of file NetworkOPs.cpp.

@@ -2112,7 +2112,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 1864 of file NetworkOPs.cpp.

+

Definition at line 1865 of file NetworkOPs.cpp.

@@ -2141,7 +2141,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2209 of file NetworkOPs.cpp.

+

Definition at line 2210 of file NetworkOPs.cpp.

@@ -2170,7 +2170,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2619 of file NetworkOPs.cpp.

+

Definition at line 2620 of file NetworkOPs.cpp.

@@ -2216,7 +2216,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2625 of file NetworkOPs.cpp.

+

Definition at line 2626 of file NetworkOPs.cpp.

@@ -2245,7 +2245,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3030 of file NetworkOPs.cpp.

+

Definition at line 3031 of file NetworkOPs.cpp.

@@ -2274,7 +2274,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3036 of file NetworkOPs.cpp.

+

Definition at line 3037 of file NetworkOPs.cpp.

@@ -2307,7 +2307,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 4138 of file NetworkOPs.cpp.

+

Definition at line 4140 of file NetworkOPs.cpp.

@@ -2336,7 +2336,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3196 of file NetworkOPs.cpp.

+

Definition at line 3197 of file NetworkOPs.cpp.

@@ -2356,7 +2356,7 @@ Static Private Attributes
-

Definition at line 3214 of file NetworkOPs.cpp.

+

Definition at line 3215 of file NetworkOPs.cpp.

@@ -2386,7 +2386,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3223 of file NetworkOPs.cpp.

+

Definition at line 3224 of file NetworkOPs.cpp.

@@ -2415,7 +2415,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3228 of file NetworkOPs.cpp.

+

Definition at line 3229 of file NetworkOPs.cpp.

@@ -2445,7 +2445,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3081 of file NetworkOPs.cpp.

+

Definition at line 3082 of file NetworkOPs.cpp.

@@ -2491,7 +2491,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 3042 of file NetworkOPs.cpp.

+

Definition at line 3043 of file NetworkOPs.cpp.

@@ -2521,7 +2521,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 2392 of file NetworkOPs.cpp.

+

Definition at line 2393 of file NetworkOPs.cpp.

@@ -2567,7 +2567,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 3614 of file NetworkOPs.cpp.

+

Definition at line 3616 of file NetworkOPs.cpp.

@@ -2613,7 +2613,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 3651 of file NetworkOPs.cpp.

+

Definition at line 3653 of file NetworkOPs.cpp.

@@ -2659,7 +2659,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 3667 of file NetworkOPs.cpp.

+

Definition at line 3669 of file NetworkOPs.cpp.

@@ -2702,7 +2702,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4031 of file NetworkOPs.cpp.

+

Definition at line 4033 of file NetworkOPs.cpp.

@@ -2757,7 +2757,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4077 of file NetworkOPs.cpp.

+

Definition at line 4079 of file NetworkOPs.cpp.

@@ -2803,7 +2803,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4088 of file NetworkOPs.cpp.

+

Definition at line 4090 of file NetworkOPs.cpp.

@@ -2843,7 +2843,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4159 of file NetworkOPs.cpp.

+

Definition at line 4161 of file NetworkOPs.cpp.

@@ -2873,7 +2873,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4199 of file NetworkOPs.cpp.

+

Definition at line 4201 of file NetworkOPs.cpp.

@@ -2903,7 +2903,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4189 of file NetworkOPs.cpp.

+

Definition at line 4191 of file NetworkOPs.cpp.

@@ -2933,7 +2933,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4207 of file NetworkOPs.cpp.

+

Definition at line 4209 of file NetworkOPs.cpp.

@@ -2979,7 +2979,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4233 of file NetworkOPs.cpp.

+

Definition at line 4235 of file NetworkOPs.cpp.

@@ -3009,7 +3009,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4263 of file NetworkOPs.cpp.

+

Definition at line 4265 of file NetworkOPs.cpp.

@@ -3049,7 +3049,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4119 of file NetworkOPs.cpp.

+

Definition at line 4121 of file NetworkOPs.cpp.

@@ -3089,7 +3089,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4129 of file NetworkOPs.cpp.

+

Definition at line 4131 of file NetworkOPs.cpp.

@@ -3119,7 +3119,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4215 of file NetworkOPs.cpp.

+

Definition at line 4217 of file NetworkOPs.cpp.

@@ -3149,7 +3149,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4225 of file NetworkOPs.cpp.

+

Definition at line 4227 of file NetworkOPs.cpp.

@@ -3179,7 +3179,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 2218 of file NetworkOPs.cpp.

+

Definition at line 2219 of file NetworkOPs.cpp.

@@ -3209,7 +3209,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4271 of file NetworkOPs.cpp.

+

Definition at line 4273 of file NetworkOPs.cpp.

@@ -3239,7 +3239,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4281 of file NetworkOPs.cpp.

+

Definition at line 4283 of file NetworkOPs.cpp.

@@ -3269,7 +3269,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4289 of file NetworkOPs.cpp.

+

Definition at line 4291 of file NetworkOPs.cpp.

@@ -3299,7 +3299,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4299 of file NetworkOPs.cpp.

+

Definition at line 4301 of file NetworkOPs.cpp.

@@ -3329,7 +3329,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4307 of file NetworkOPs.cpp.

+

Definition at line 4309 of file NetworkOPs.cpp.

@@ -3359,7 +3359,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4323 of file NetworkOPs.cpp.

+

Definition at line 4325 of file NetworkOPs.cpp.

@@ -3389,7 +3389,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4331 of file NetworkOPs.cpp.

+

Definition at line 4333 of file NetworkOPs.cpp.

@@ -3419,7 +3419,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4341 of file NetworkOPs.cpp.

+

Definition at line 4343 of file NetworkOPs.cpp.

@@ -3449,7 +3449,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 2502 of file NetworkOPs.cpp.

+

Definition at line 2503 of file NetworkOPs.cpp.

@@ -3479,7 +3479,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4349 of file NetworkOPs.cpp.

+

Definition at line 4351 of file NetworkOPs.cpp.

@@ -3509,7 +3509,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4359 of file NetworkOPs.cpp.

+

Definition at line 4361 of file NetworkOPs.cpp.

@@ -3539,7 +3539,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4366 of file NetworkOPs.cpp.

+

Definition at line 4368 of file NetworkOPs.cpp.

@@ -3579,7 +3579,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4379 of file NetworkOPs.cpp.

+

Definition at line 4381 of file NetworkOPs.cpp.

@@ -3609,7 +3609,7 @@ Static Private Attributes

Implements ripple::InfoSub::Source.

-

Definition at line 4389 of file NetworkOPs.cpp.

+

Definition at line 4391 of file NetworkOPs.cpp.

@@ -3638,7 +3638,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 587 of file NetworkOPs.cpp.

+

Definition at line 588 of file NetworkOPs.cpp.

@@ -3668,7 +3668,7 @@ Static Private Attributes

Implements ripple::NetworkOPs.

-

Definition at line 4316 of file NetworkOPs.cpp.

+

Definition at line 4318 of file NetworkOPs.cpp.

@@ -3718,7 +3718,7 @@ Static Private Attributes
-

Definition at line 960 of file NetworkOPs.cpp.

+

Definition at line 961 of file NetworkOPs.cpp.

@@ -3745,7 +3745,7 @@ Static Private Attributes
-

Definition at line 992 of file NetworkOPs.cpp.

+

Definition at line 993 of file NetworkOPs.cpp.

@@ -3772,7 +3772,7 @@ Static Private Attributes
-

Definition at line 1006 of file NetworkOPs.cpp.

+

Definition at line 1007 of file NetworkOPs.cpp.

@@ -3799,7 +3799,7 @@ Static Private Attributes
-

Definition at line 1035 of file NetworkOPs.cpp.

+

Definition at line 1036 of file NetworkOPs.cpp.

@@ -3826,7 +3826,7 @@ Static Private Attributes
-

Definition at line 1118 of file NetworkOPs.cpp.

+

Definition at line 1119 of file NetworkOPs.cpp.

@@ -3882,7 +3882,7 @@ Static Private Attributes
-

Definition at line 3236 of file NetworkOPs.cpp.

+

Definition at line 3237 of file NetworkOPs.cpp.

@@ -3926,7 +3926,7 @@ Static Private Attributes
-

Definition at line 3345 of file NetworkOPs.cpp.

+

Definition at line 3347 of file NetworkOPs.cpp.

@@ -3970,7 +3970,7 @@ Static Private Attributes
-

Definition at line 3401 of file NetworkOPs.cpp.

+

Definition at line 3403 of file NetworkOPs.cpp.

@@ -4014,7 +4014,7 @@ Static Private Attributes
-

Definition at line 3535 of file NetworkOPs.cpp.

+

Definition at line 3537 of file NetworkOPs.cpp.

@@ -4041,7 +4041,7 @@ Static Private Attributes
-

Definition at line 2297 of file NetworkOPs.cpp.

+

Definition at line 2298 of file NetworkOPs.cpp.

@@ -4069,7 +4069,7 @@ Static Private Attributes
-

Definition at line 2365 of file NetworkOPs.cpp.

+

Definition at line 2366 of file NetworkOPs.cpp.

@@ -4097,7 +4097,7 @@ Static Private Attributes
-

Definition at line 931 of file NetworkOPs.cpp.

+

Definition at line 932 of file NetworkOPs.cpp.

@@ -4136,7 +4136,7 @@ Static Private Attributes
Note
called while holding mSubLock
-

Definition at line 3985 of file NetworkOPs.cpp.

+

Definition at line 3987 of file NetworkOPs.cpp.

@@ -4164,7 +4164,7 @@ Static Private Attributes
-

Definition at line 3695 of file NetworkOPs.cpp.

+

Definition at line 3697 of file NetworkOPs.cpp.

@@ -4192,7 +4192,7 @@ Static Private Attributes
-

Definition at line 1022 of file NetworkOPs.cpp.

+

Definition at line 1023 of file NetworkOPs.cpp.

@@ -4219,7 +4219,7 @@ Static Private Attributes
-

Definition at line 4754 of file NetworkOPs.cpp.

+

Definition at line 4756 of file NetworkOPs.cpp.

@@ -4272,7 +4272,7 @@ Static Private Attributes
-

Definition at line 126 of file NetworkOPs.cpp.

+

Definition at line 127 of file NetworkOPs.cpp.

@@ -4296,7 +4296,7 @@ Static Private Attributes
-

Definition at line 737 of file NetworkOPs.cpp.

+

Definition at line 738 of file NetworkOPs.cpp.

@@ -4320,7 +4320,7 @@ Static Private Attributes
-

Definition at line 738 of file NetworkOPs.cpp.

+

Definition at line 739 of file NetworkOPs.cpp.

@@ -4344,7 +4344,7 @@ Static Private Attributes
-

Definition at line 740 of file NetworkOPs.cpp.

+

Definition at line 741 of file NetworkOPs.cpp.

@@ -4368,7 +4368,7 @@ Static Private Attributes
-

Definition at line 742 of file NetworkOPs.cpp.

+

Definition at line 743 of file NetworkOPs.cpp.

@@ -4392,7 +4392,7 @@ Static Private Attributes
-

Definition at line 744 of file NetworkOPs.cpp.

+

Definition at line 745 of file NetworkOPs.cpp.

@@ -4416,7 +4416,7 @@ Static Private Attributes
-

Definition at line 746 of file NetworkOPs.cpp.

+

Definition at line 747 of file NetworkOPs.cpp.

@@ -4440,7 +4440,7 @@ Static Private Attributes
-

Definition at line 747 of file NetworkOPs.cpp.

+

Definition at line 748 of file NetworkOPs.cpp.

@@ -4464,7 +4464,7 @@ Static Private Attributes
-

Definition at line 748 of file NetworkOPs.cpp.

+

Definition at line 749 of file NetworkOPs.cpp.

@@ -4488,7 +4488,7 @@ Static Private Attributes
-

Definition at line 749 of file NetworkOPs.cpp.

+

Definition at line 750 of file NetworkOPs.cpp.

@@ -4512,7 +4512,7 @@ Static Private Attributes
-

Definition at line 751 of file NetworkOPs.cpp.

+

Definition at line 752 of file NetworkOPs.cpp.

@@ -4536,7 +4536,7 @@ Static Private Attributes
-

Definition at line 752 of file NetworkOPs.cpp.

+

Definition at line 753 of file NetworkOPs.cpp.

@@ -4560,7 +4560,7 @@ Static Private Attributes
-

Definition at line 753 of file NetworkOPs.cpp.

+

Definition at line 754 of file NetworkOPs.cpp.

@@ -4584,7 +4584,7 @@ Static Private Attributes
-

Definition at line 754 of file NetworkOPs.cpp.

+

Definition at line 755 of file NetworkOPs.cpp.

@@ -4608,7 +4608,7 @@ Static Private Attributes
-

Definition at line 756 of file NetworkOPs.cpp.

+

Definition at line 757 of file NetworkOPs.cpp.

@@ -4632,7 +4632,7 @@ Static Private Attributes
-

Definition at line 758 of file NetworkOPs.cpp.

+

Definition at line 759 of file NetworkOPs.cpp.

@@ -4656,7 +4656,7 @@ Static Private Attributes
-

Definition at line 759 of file NetworkOPs.cpp.

+

Definition at line 760 of file NetworkOPs.cpp.

@@ -4680,7 +4680,7 @@ Static Private Attributes
-

Definition at line 761 of file NetworkOPs.cpp.

+

Definition at line 762 of file NetworkOPs.cpp.

@@ -4704,7 +4704,7 @@ Static Private Attributes
-

Definition at line 763 of file NetworkOPs.cpp.

+

Definition at line 764 of file NetworkOPs.cpp.

@@ -4728,7 +4728,7 @@ Static Private Attributes
-

Definition at line 765 of file NetworkOPs.cpp.

+

Definition at line 766 of file NetworkOPs.cpp.

@@ -4752,7 +4752,7 @@ Static Private Attributes
-

Definition at line 766 of file NetworkOPs.cpp.

+

Definition at line 767 of file NetworkOPs.cpp.

@@ -4776,7 +4776,7 @@ Static Private Attributes
-

Definition at line 768 of file NetworkOPs.cpp.

+

Definition at line 769 of file NetworkOPs.cpp.

@@ -4800,7 +4800,7 @@ Static Private Attributes
-

Definition at line 770 of file NetworkOPs.cpp.

+

Definition at line 771 of file NetworkOPs.cpp.

@@ -4824,7 +4824,7 @@ Static Private Attributes
-

Definition at line 785 of file NetworkOPs.cpp.

+

Definition at line 786 of file NetworkOPs.cpp.

@@ -4848,7 +4848,7 @@ Static Private Attributes
-

Definition at line 787 of file NetworkOPs.cpp.

+

Definition at line 788 of file NetworkOPs.cpp.

@@ -4872,7 +4872,7 @@ Static Private Attributes
-

Definition at line 789 of file NetworkOPs.cpp.

+

Definition at line 790 of file NetworkOPs.cpp.

@@ -4896,7 +4896,7 @@ Static Private Attributes
-

Definition at line 792 of file NetworkOPs.cpp.

+

Definition at line 793 of file NetworkOPs.cpp.

@@ -4920,7 +4920,7 @@ Static Private Attributes
-

Definition at line 795 of file NetworkOPs.cpp.

+

Definition at line 796 of file NetworkOPs.cpp.

@@ -4944,7 +4944,7 @@ Static Private Attributes
-

Definition at line 798 of file NetworkOPs.cpp.

+

Definition at line 799 of file NetworkOPs.cpp.

@@ -4968,7 +4968,7 @@ Static Private Attributes
-

Definition at line 799 of file NetworkOPs.cpp.

+

Definition at line 800 of file NetworkOPs.cpp.

@@ -4992,7 +4992,7 @@ Static Private Attributes
-

Definition at line 800 of file NetworkOPs.cpp.

+

Definition at line 801 of file NetworkOPs.cpp.

@@ -5016,7 +5016,7 @@ Static Private Attributes
-

Definition at line 801 of file NetworkOPs.cpp.

+

Definition at line 802 of file NetworkOPs.cpp.

@@ -5040,7 +5040,7 @@ Static Private Attributes
-

Definition at line 803 of file NetworkOPs.cpp.

+

Definition at line 804 of file NetworkOPs.cpp.

@@ -5064,7 +5064,7 @@ Static Private Attributes
-

Definition at line 805 of file NetworkOPs.cpp.

+

Definition at line 806 of file NetworkOPs.cpp.

@@ -5088,7 +5088,7 @@ Static Private Attributes
-

Definition at line 806 of file NetworkOPs.cpp.

+

Definition at line 807 of file NetworkOPs.cpp.

@@ -5112,7 +5112,7 @@ Static Private Attributes
-

Definition at line 860 of file NetworkOPs.cpp.

+

Definition at line 861 of file NetworkOPs.cpp.

@@ -5136,7 +5136,7 @@ Static Private Attributes
-

Definition at line 861 of file NetworkOPs.cpp.

+

Definition at line 862 of file NetworkOPs.cpp.

diff --git a/classripple_1_1NetworkOPsImp_1_1StateAccounting.html b/classripple_1_1NetworkOPsImp_1_1StateAccounting.html index be59093320..f4db26a8f3 100644 --- a/classripple_1_1NetworkOPsImp_1_1StateAccounting.html +++ b/classripple_1_1NetworkOPsImp_1_1StateAccounting.html @@ -147,7 +147,7 @@ Static Private Attributes

This data can be polled through server_info and represented by monitoring systems similarly to how bandwidth, CPU, and other counter-based metrics are managed.

State accounting is more accurate than periodic sampling of server state. With periodic sampling, it is very likely that state transitions are missed, and accuracy of time spent in each state is very rough.

-

Definition at line 142 of file NetworkOPs.cpp.

+

Definition at line 143 of file NetworkOPs.cpp.

Constructor & Destructor Documentation

◆ StateAccounting()

@@ -172,7 +172,7 @@ Static Private Attributes
-

Definition at line 162 of file NetworkOPs.cpp.

+

Definition at line 163 of file NetworkOPs.cpp.

@@ -202,7 +202,7 @@ Static Private Attributes -

Definition at line 4792 of file NetworkOPs.cpp.

+

Definition at line 4794 of file NetworkOPs.cpp.

@@ -225,7 +225,7 @@ Static Private Attributes

Output state counters in JSON format.

@obj Json object to which to add state accounting data.

-

Definition at line 4813 of file NetworkOPs.cpp.

+

Definition at line 4815 of file NetworkOPs.cpp.

@@ -244,7 +244,7 @@ Static Private Attributes
-

Definition at line 194 of file NetworkOPs.cpp.

+

Definition at line 195 of file NetworkOPs.cpp.

@@ -269,7 +269,7 @@ Static Private Attributes
-

Definition at line 152 of file NetworkOPs.cpp.

+

Definition at line 153 of file NetworkOPs.cpp.

@@ -293,7 +293,7 @@ Static Private Attributes
-

Definition at line 153 of file NetworkOPs.cpp.

+

Definition at line 154 of file NetworkOPs.cpp.

@@ -317,7 +317,7 @@ Static Private Attributes
-

Definition at line 154 of file NetworkOPs.cpp.

+

Definition at line 155 of file NetworkOPs.cpp.

@@ -344,7 +344,7 @@ Static Private Attributes
std::chrono::steady_clock::now()
std::chrono::steady_clock::now
T now(T... args)
-

Definition at line 155 of file NetworkOPs.cpp.

+

Definition at line 156 of file NetworkOPs.cpp.

@@ -368,7 +368,7 @@ Static Private Attributes
-

Definition at line 157 of file NetworkOPs.cpp.

+

Definition at line 158 of file NetworkOPs.cpp.

@@ -392,7 +392,7 @@ Static Private Attributes
-

Definition at line 158 of file NetworkOPs.cpp.

+

Definition at line 159 of file NetworkOPs.cpp.

@@ -422,9 +422,9 @@ Static Private Attributes
Json::StaticString(stateNames[3]),
Json::StaticString(stateNames[4])}}
Json::StaticString
Lightweight wrapper to tag static string.
Definition: json_value.h:64
-
ripple::stateNames
static std::array< char const *, 5 > const stateNames
Definition: NetworkOPs.cpp:870
+
ripple::stateNames
static std::array< char const *, 5 > const stateNames
Definition: NetworkOPs.cpp:871
-

Definition at line 159 of file NetworkOPs.cpp.

+

Definition at line 160 of file NetworkOPs.cpp.

diff --git a/classripple_1_1NetworkOPsImp_1_1TransactionStatus.html b/classripple_1_1NetworkOPsImp_1_1TransactionStatus.html index 7af5f81e86..c0b25219f7 100644 --- a/classripple_1_1NetworkOPsImp_1_1TransactionStatus.html +++ b/classripple_1_1NetworkOPsImp_1_1TransactionStatus.html @@ -158,7 +158,7 @@ Public Attributes

Detailed Description

Transaction with input flags and results to be applied in batches.

-

Definition at line 93 of file NetworkOPs.cpp.

+

Definition at line 94 of file NetworkOPs.cpp.

Constructor & Destructor Documentation

◆ TransactionStatus()

@@ -198,7 +198,7 @@ Public Attributes
-

Definition at line 103 of file NetworkOPs.cpp.

+

Definition at line 104 of file NetworkOPs.cpp.

@@ -215,7 +215,7 @@ Public Attributes
-

Definition at line 96 of file NetworkOPs.cpp.

+

Definition at line 97 of file NetworkOPs.cpp.

@@ -231,7 +231,7 @@ Public Attributes
-

Definition at line 97 of file NetworkOPs.cpp.

+

Definition at line 98 of file NetworkOPs.cpp.

@@ -247,7 +247,7 @@ Public Attributes
-

Definition at line 98 of file NetworkOPs.cpp.

+

Definition at line 99 of file NetworkOPs.cpp.

@@ -263,7 +263,7 @@ Public Attributes
-

Definition at line 99 of file NetworkOPs.cpp.

+

Definition at line 100 of file NetworkOPs.cpp.

@@ -279,7 +279,7 @@ Public Attributes
-

Definition at line 100 of file NetworkOPs.cpp.

+

Definition at line 101 of file NetworkOPs.cpp.

@@ -295,7 +295,7 @@ Public Attributes
-

Definition at line 101 of file NetworkOPs.cpp.

+

Definition at line 102 of file NetworkOPs.cpp.

diff --git a/classripple_1_1test_1_1Subscribe__test-members.html b/classripple_1_1test_1_1Subscribe__test-members.html index e2f0f53c01..5d7a792698 100644 --- a/classripple_1_1test_1_1Subscribe__test-members.html +++ b/classripple_1_1test_1_1Subscribe__test-members.html @@ -106,19 +106,20 @@ $(function() { testHistoryTxStream()ripple::test::Subscribe_test testLedger()ripple::test::Subscribe_test testManifests()ripple::test::Subscribe_test - testServer()ripple::test::Subscribe_test - testSubBookChanges()ripple::test::Subscribe_test - testSubByUrl()ripple::test::Subscribe_test - testSubErrors(bool subscribe)ripple::test::Subscribe_test - testTransactions_APIv1()ripple::test::Subscribe_test - testTransactions_APIv2()ripple::test::Subscribe_test - testValidations(FeatureBitset features)ripple::test::Subscribe_test - this_suite()beast::unit_test::suitestatic - unexcept(F &&f, String const &reason)beast::unit_test::suite - unexcept(F &&f)beast::unit_test::suite - unexpected(Condition shouldBeFalse, String const &reason)beast::unit_test::suite - unexpected(Condition shouldBeFalse)beast::unit_test::suite - ~suite()=defaultbeast::unit_test::suitevirtual + testNFToken(FeatureBitset features)ripple::test::Subscribe_test + testServer()ripple::test::Subscribe_test + testSubBookChanges()ripple::test::Subscribe_test + testSubByUrl()ripple::test::Subscribe_test + testSubErrors(bool subscribe)ripple::test::Subscribe_test + testTransactions_APIv1()ripple::test::Subscribe_test + testTransactions_APIv2()ripple::test::Subscribe_test + testValidations(FeatureBitset features)ripple::test::Subscribe_test + this_suite()beast::unit_test::suitestatic + unexcept(F &&f, String const &reason)beast::unit_test::suite + unexcept(F &&f)beast::unit_test::suite + unexpected(Condition shouldBeFalse, String const &reason)beast::unit_test::suite + unexpected(Condition shouldBeFalse)beast::unit_test::suite + ~suite()=defaultbeast::unit_test::suitevirtual