xrpld
Loading...
Searching...
No Matches
DepositAuthorized.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
3
4#include <xrpl/basics/Slice.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/core/ServiceRegistry.h>
7#include <xrpl/json/json_value.h>
8#include <xrpl/ledger/ReadView.h>
9#include <xrpl/ledger/helpers/CredentialHelpers.h>
10#include <xrpl/protocol/AccountID.h>
11#include <xrpl/protocol/ErrorCodes.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/LedgerFormats.h>
14#include <xrpl/protocol/Protocol.h>
15#include <xrpl/protocol/RPCErr.h>
16#include <xrpl/protocol/SField.h>
17#include <xrpl/protocol/jss.h>
18
19#include <memory>
20#include <set>
21#include <utility>
22#include <vector>
23
24namespace xrpl {
25
26// {
27// source_account : <ident>
28// destination_account : <ident>
29// ledger_hash : <ledger>
30// ledger_index : <ledger_index>
31// credentials : [<credentialID>,...]
32// }
33
34json::Value
36{
37 json::Value const& params = context.params;
38
39 // Validate source_account.
40 if (!params.isMember(jss::source_account))
41 return RPC::missingFieldError(jss::source_account);
42 if (!params[jss::source_account].isString())
43 {
44 return RPC::makeError(
45 RpcInvalidParams, RPC::expectedFieldMessage(jss::source_account, "a string"));
46 }
47
48 auto srcID = parseBase58<AccountID>(params[jss::source_account].asString());
49 if (!srcID)
51 auto const srcAcct{srcID.value()};
52
53 // Validate destination_account.
54 if (!params.isMember(jss::destination_account))
55 return RPC::missingFieldError(jss::destination_account);
56 if (!params[jss::destination_account].isString())
57 {
58 return RPC::makeError(
59 RpcInvalidParams, RPC::expectedFieldMessage(jss::destination_account, "a string"));
60 }
61
62 auto dstID = parseBase58<AccountID>(params[jss::destination_account].asString());
63 if (!dstID)
65 auto const dstAcct{dstID.value()};
66
67 // Validate ledger.
69 json::Value result = RPC::lookupLedger(ledger, context);
70
71 if (!ledger)
72 return result;
73
74 // If source account is not in the ledger it can't be authorized.
75 if (!ledger->exists(keylet::account(srcAcct)))
76 {
78 return result;
79 }
80
81 // If destination account is not in the ledger you can't deposit to it, eh?
82 auto const sleDest = ledger->read(keylet::account(dstAcct));
83 if (!sleDest)
84 {
86 return result;
87 }
88
89 bool const reqAuth = sleDest->isFlag(lsfDepositAuth) && (srcAcct != dstAcct);
90 bool const credentialsPresent = params.isMember(jss::credentials);
91
94 if (credentialsPresent)
95 {
96 auto const& creds(params[jss::credentials]);
97 if (!creds.isArray() || !creds)
98 {
99 return RPC::makeError(
102 jss::credentials, "is non-empty array of CredentialID(hash256)"));
103 }
104 if (creds.size() > kMaxCredentialsArraySize)
105 {
106 return RPC::makeError(
107 RpcInvalidParams, RPC::expectedFieldMessage(jss::credentials, "array too long"));
108 }
109
110 lifeExtender.reserve(creds.size());
111 for (auto const& jo : creds)
112 {
113 if (!jo.isString())
114 {
115 return RPC::makeError(
118 jss::credentials, "an array of CredentialID(hash256)"));
119 }
120
121 uint256 credH;
122 auto const credS = jo.asString();
123 if (!credH.parseHex(credS))
124 {
125 return RPC::makeError(
128 jss::credentials, "an array of CredentialID(hash256)"));
129 }
130
131 SLE::const_pointer sleCred = ledger->read(keylet::credential(credH));
132 if (!sleCred)
133 {
134 RPC::injectError(RpcBadCredentials, "credentials don't exist", result);
135 return result;
136 }
137
138 if (!sleCred->isFlag(lsfAccepted))
139 {
140 RPC::injectError(RpcBadCredentials, "credentials aren't accepted", result);
141 return result;
142 }
143
144 if (credentials::checkExpired(*sleCred, ledger->header().parentCloseTime))
145 {
146 RPC::injectError(RpcBadCredentials, "credentials are expired", result);
147 return result;
148 }
149
150 if ((*sleCred)[sfSubject] != srcAcct)
151 {
153 RpcBadCredentials, "credentials doesn't belong to the root account", result);
154 return result;
155 }
156
157 auto [it, ins] = sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]);
158 if (!ins)
159 {
160 RPC::injectError(RpcBadCredentials, "duplicates in credentials", result);
161 return result;
162 }
163 lifeExtender.push_back(std::move(sleCred));
164 }
165 }
166
167 // If the two accounts are the same OR if that flag is
168 // not set, then the deposit should be fine.
169 bool depositAuthorized = true;
170 if (reqAuth)
171 {
172 depositAuthorized = ledger->exists(keylet::depositPreauth(dstAcct, srcAcct)) ||
173 (credentialsPresent && ledger->exists(keylet::depositPreauth(dstAcct, sorted)));
174 }
175
176 result[jss::source_account] = params[jss::source_account].asString();
177 result[jss::destination_account] = params[jss::destination_account].asString();
178 if (credentialsPresent)
179 result[jss::credentials] = params[jss::credentials];
180
181 result[jss::deposit_authorized] = depositAuthorized;
182 return result;
183}
184
185} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
std::shared_ptr< STLedgerEntry const > const_pointer
T emplace(T... args)
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.
json::Value makeError(ErrorCodeI code)
Returns a new json object that reflects the error code.
void injectError(ErrorCodeI code, json::Value &json)
Add or update the json update to reflect the error code.
std::string expectedFieldMessage(std::string const &name, std::string const &type)
Definition ErrorCodes.h:285
json::Value missingFieldError(std::string const &name)
Definition ErrorCodes.h:231
bool checkExpired(SLE const &sleCredential, NetClock::time_point const &closed)
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition Indexes.cpp:328
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition Indexes.cpp:545
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ RpcDstActNotFound
Definition ErrorCodes.h:87
@ RpcBadCredentials
Definition ErrorCodes.h:134
@ RpcActMalformed
Definition ErrorCodes.h:72
@ RpcInvalidParams
Definition ErrorCodes.h:66
@ RpcSrcActNotFound
Definition ErrorCodes.h:104
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
json::Value rpcError(ErrorCodeI iError)
Definition RPCErr.cpp:13
constexpr std::size_t kMaxCredentialsArraySize
The maximum number of credentials can be passed in array.
Definition Protocol.h:228
json::Value doDepositAuthorized(RPC::JsonContext &)
BaseUInt< 256 > uint256
Definition base_uint.h:562
T push_back(T... args)
T reserve(T... args)
json::Value params
Definition Context.h:43