xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
xrpld
rpc
handlers
orderbook
RipplePathFind.cpp
1
#include <xrpld/app/ledger/LedgerMaster.h>
2
#include <xrpld/rpc/Context.h>
3
#include <xrpld/rpc/Role.h>
4
#include <xrpld/rpc/detail/LegacyPathFind.h>
5
#include <xrpld/rpc/detail/PathRequest.h>
6
#include <xrpld/rpc/detail/PathRequestManager.h>
7
#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
8
#include <xrpld/rpc/detail/Tuning.h>
9
10
#include <xrpl/core/JobQueue.h>
11
#include <xrpl/json/json_value.h>
12
#include <xrpl/protocol/ErrorCodes.h>
13
#include <xrpl/protocol/RPCErr.h>
14
#include <xrpl/protocol/jss.h>
15
#include <xrpl/resource/Fees.h>
16
17
#include <
memory
>
18
#include <
utility
>
19
20
namespace
xrpl
{
21
22
// This interface is deprecated.
23
json::Value
24
doRipplePathFind
(
rpc::JsonContext
& context)
25
{
26
if
(context.
app
.
config
().
pathSearchMax
== 0)
27
return
rpcError
(
RpcNotSupported
);
28
29
context.
loadType
=
resource::kFeeHeavyBurdenRpc
;
30
31
std::shared_ptr<ReadView const>
lpLedger;
32
json::Value
jvResult;
33
34
if
(!context.
app
.
config
().
standalone
() && !context.
params
.
isMember
(jss::ledger) &&
35
!context.
params
.
isMember
(jss::ledger_index) && !context.
params
.
isMember
(jss::ledger_hash))
36
{
37
// No ledger specified, use pathfinding defaults
38
// and dispatch to pathfinding engine
39
if
(context.
app
.
getLedgerMaster
().
getValidatedLedgerAge
() >
40
rpc::tuning::kMaxValidatedLedgerAge
)
41
{
42
if
(context.
apiVersion
== 1)
43
return
rpcError
(
RpcNoNetwork
);
44
return
rpcError
(
RpcNotSynced
);
45
}
46
47
PathRequest::pointer
request;
48
lpLedger = context.
ledgerMaster
.
getClosedLedger
();
49
50
// It doesn't look like there's much odd happening here, but you should
51
// be aware this code runs in a JobQueue::Coro, which is a coroutine.
52
// And we may be flipping around between threads. Here's an overview:
53
//
54
// 1. We're running doRipplePathFind() due to a call to
55
// ripple_path_find. doRipplePathFind() is currently running
56
// inside of a JobQueue::Coro using a JobQueue thread.
57
//
58
// 2. doRipplePathFind's call to makeLegacyPathRequest() enqueues the
59
// path-finding request. That request will (probably) run at some
60
// indeterminate future time on a (probably different) JobQueue
61
// thread.
62
//
63
// 3. As a continuation from that path-finding JobQueue thread, the
64
// coroutine we're currently running in (!) is posted to the
65
// JobQueue. Because it is a continuation, that post won't
66
// happen until the path-finding request completes.
67
//
68
// 4. Once the continuation is enqueued, and we have reason to think
69
// the path-finding job is likely to run, then the coroutine we're
70
// running in yield()s. That means it surrenders its thread in
71
// the JobQueue. The coroutine is suspended, but ready to run,
72
// because it is kept resident by a shared_ptr in the
73
// path-finding continuation.
74
//
75
// 5. If all goes well then path-finding runs on a JobQueue thread
76
// and executes its continuation. The continuation posts this
77
// same coroutine (!) to the JobQueue.
78
//
79
// 6. When the JobQueue calls this coroutine, this coroutine resumes
80
// from the line below the coro->yield() and returns the
81
// path-finding result.
82
//
83
// With so many moving parts, what could go wrong?
84
//
85
// Just in terms of the JobQueue refusing to add jobs at shutdown
86
// there are two specific things that can go wrong.
87
//
88
// 1. The path-finding Job queued by makeLegacyPathRequest() might be
89
// rejected (because we're shutting down).
90
//
91
// Fortunately this problem can be addressed by looking at the
92
// return value of makeLegacyPathRequest(). If
93
// makeLegacyPathRequest() cannot get a thread to run the path-find
94
// on, then it returns an empty request.
95
//
96
// 2. The path-finding job might run, but the Coro::post() might be
97
// rejected by the JobQueue (because we're shutting down).
98
//
99
// We handle this case by resuming (not posting) the Coro.
100
// By resuming the Coro, we allow the Coro to run to completion
101
// on the current thread instead of requiring that it run on a
102
// new thread from the JobQueue.
103
//
104
// Both of these failure modes are hard to recreate in a unit test
105
// because they are so dependent on inter-thread timing. However
106
// the failure modes can be observed by synchronously (inside the
107
// xrpld source code) shutting down the application. The code to
108
// do so looks like this:
109
//
110
// context.app.signalStop();
111
// while (! context.app.getJobQueue().jobCounter().joined()) { }
112
//
113
// The first line starts the process of shutting down the app.
114
// The second line waits until no more jobs can be added to the
115
// JobQueue before letting the thread continue.
116
//
117
// May 2017
118
jvResult = context.
app
.
getPathRequestManager
().
makeLegacyPathRequest
(
119
request,
120
[&context]() {
121
// Copying the shared_ptr keeps the coroutine alive up
122
// through the return. Otherwise the storage under the
123
// captured reference could evaporate when we return from
124
// coroCopy->resume(). This is not strictly necessary, but
125
// will make maintenance easier.
126
std::shared_ptr<JobQueue::Coro>
const
coroCopy{context.
coro
};
127
if
(!coroCopy->post())
128
{
129
// The post() failed, so we won't get a thread to let
130
// the Coro finish. We'll call Coro::resume() so the
131
// Coro can finish on our thread. Otherwise the
132
// application will hang on shutdown.
133
coroCopy->resume();
134
}
135
},
136
context.
consumer
,
137
lpLedger,
138
context.
params
);
139
if
(request)
140
{
141
context.
coro
->yield();
142
jvResult = request->
doStatus
(context.
params
);
143
}
144
145
return
jvResult;
146
}
147
148
// The caller specified a ledger
149
jvResult =
rpc::lookupLedger
(lpLedger, context);
150
if
(!lpLedger)
151
return
jvResult;
152
153
rpc::LegacyPathFind
const
lpf(
isUnlimited
(context.
role
), context.
app
);
154
if
(!lpf.
isOk
())
155
return
rpcError
(
RpcTooBusy
);
156
157
auto
result = context.
app
.
getPathRequestManager
().
doLegacyPathRequest
(
158
context.
consumer
, lpLedger, context.
params
);
159
160
for
(
auto
& fieldName : jvResult.
getMemberNames
())
161
result[fieldName] = std::move(jvResult[fieldName]);
162
163
return
result;
164
}
165
166
}
// namespace xrpl
json::Value
Represents a JSON value.
Definition
json_value.h:117
json::Value::getMemberNames
Members getMemberNames() const
Return a list of the member names.
Definition
json_value.cpp:1071
json::Value::isMember
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition
json_value.cpp:1049
xrpl::Application::config
virtual Config & config()=0
xrpl::Config::pathSearchMax
int pathSearchMax
Definition
src/xrpld/core/Config.h:201
xrpl::Config::standalone
bool standalone() const
Definition
src/xrpld/core/Config.h:360
xrpl::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition
LedgerMaster.cpp:229
xrpl::LedgerMaster::getClosedLedger
std::shared_ptr< Ledger const > getClosedLedger()
The finalized ledger is the last closed/accepted ledger.
Definition
LedgerMaster.h:193
xrpl::PathRequestManager::makeLegacyPathRequest
json::Value makeLegacyPathRequest(PathRequest::pointer &req, std::function< void(void)> completion, resource::Consumer &consumer, std::shared_ptr< ReadView const > const &inLedger, json::Value const &request)
Definition
PathRequestManager.cpp:254
xrpl::PathRequestManager::doLegacyPathRequest
json::Value doLegacyPathRequest(resource::Consumer &consumer, std::shared_ptr< ReadView const > const &inLedger, json::Value const &request)
Definition
PathRequestManager.cpp:287
xrpl::PathRequest::doStatus
json::Value doStatus(json::Value const &) override
Definition
PathRequest.cpp:496
xrpl::PathRequest::pointer
std::shared_ptr< PathRequest > pointer
Definition
PathRequest.h:48
xrpl::ServiceRegistry::getPathRequestManager
virtual PathRequestManager & getPathRequestManager()=0
xrpl::ServiceRegistry::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
xrpl::rpc::LegacyPathFind
Definition
LegacyPathFind.h:12
xrpl::rpc::LegacyPathFind::isOk
bool isOk() const
Definition
LegacyPathFind.h:18
memory
xrpl::resource::kFeeHeavyBurdenRpc
Charge const kFeeHeavyBurdenRpc
xrpl::rpc::tuning::kMaxValidatedLedgerAge
constexpr auto kMaxValidatedLedgerAge
Definition
src/xrpld/rpc/detail/Tuning.h:69
xrpl::rpc::lookupLedger
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext const &context, json::Value &result)
Looks up a ledger from a request and fills a json::Value with ledger data.
Definition
RPCLedgerHelpers.cpp:390
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::RpcNotSupported
@ RpcNotSupported
Definition
ErrorCodes.h:115
xrpl::RpcNoNetwork
@ RpcNoNetwork
Definition
ErrorCodes.h:49
xrpl::RpcNotSynced
@ RpcNotSynced
Definition
ErrorCodes.h:50
xrpl::RpcTooBusy
@ RpcTooBusy
Definition
ErrorCodes.h:39
xrpl::doRipplePathFind
json::Value doRipplePathFind(rpc::JsonContext &)
Definition
RipplePathFind.cpp:24
xrpl::rpcError
json::Value rpcError(ErrorCodeI iError)
Definition
RPCErr.cpp:13
xrpl::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition
Role.cpp:115
std::shared_ptr
xrpl::rpc::Context::coro
std::shared_ptr< JobQueue::Coro > coro
Definition
Context.h:35
xrpl::rpc::Context::loadType
resource::Charge & loadType
Definition
Context.h:30
xrpl::rpc::Context::role
Role role
Definition
Context.h:34
xrpl::rpc::Context::apiVersion
unsigned int apiVersion
Definition
Context.h:37
xrpl::rpc::Context::app
Application & app
Definition
Context.h:29
xrpl::rpc::Context::consumer
resource::Consumer & consumer
Definition
Context.h:33
xrpl::rpc::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition
Context.h:32
xrpl::rpc::JsonContext
Definition
Context.h:41
xrpl::rpc::JsonContext::params
json::Value params
Definition
Context.h:51
utility
Generated by
1.17.0