rippled
Loading...
Searching...
No Matches
DepositAuthorized.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/detail/RPCLedgerHelpers.h>
3
4#include <xrpl/ledger/CredentialHelpers.h>
5#include <xrpl/ledger/ReadView.h>
6#include <xrpl/protocol/ErrorCodes.h>
7#include <xrpl/protocol/Indexes.h>
8#include <xrpl/protocol/RPCErr.h>
9#include <xrpl/protocol/jss.h>
10
11namespace xrpl {
12
13// {
14// source_account : <ident>
15// destination_account : <ident>
16// ledger_hash : <ledger>
17// ledger_index : <ledger_index>
18// credentials : [<credentialID>,...]
19// }
20
23{
24 Json::Value const& params = context.params;
25
26 // Validate source_account.
27 if (!params.isMember(jss::source_account))
28 return RPC::missing_field_error(jss::source_account);
29 if (!params[jss::source_account].isString())
30 return RPC::make_error(rpcINVALID_PARAMS, RPC::expected_field_message(jss::source_account, "a string"));
31
32 auto srcID = parseBase58<AccountID>(params[jss::source_account].asString());
33 if (!srcID)
35 auto const srcAcct{std::move(srcID.value())};
36
37 // Validate destination_account.
38 if (!params.isMember(jss::destination_account))
39 return RPC::missing_field_error(jss::destination_account);
40 if (!params[jss::destination_account].isString())
41 return RPC::make_error(rpcINVALID_PARAMS, RPC::expected_field_message(jss::destination_account, "a string"));
42
43 auto dstID = parseBase58<AccountID>(params[jss::destination_account].asString());
44 if (!dstID)
46 auto const dstAcct{std::move(dstID.value())};
47
48 // Validate ledger.
50 Json::Value result = RPC::lookupLedger(ledger, context);
51
52 if (!ledger)
53 return result;
54
55 // If source account is not in the ledger it can't be authorized.
56 if (!ledger->exists(keylet::account(srcAcct)))
57 {
59 return result;
60 }
61
62 // If destination account is not in the ledger you can't deposit to it, eh?
63 auto const sleDest = ledger->read(keylet::account(dstAcct));
64 if (!sleDest)
65 {
67 return result;
68 }
69
70 bool const reqAuth = (sleDest->getFlags() & lsfDepositAuth) && (srcAcct != dstAcct);
71 bool const credentialsPresent = params.isMember(jss::credentials);
72
75 if (credentialsPresent)
76 {
77 auto const& creds(params[jss::credentials]);
78 if (!creds.isArray() || !creds)
79 {
80 return RPC::make_error(
82 RPC::expected_field_message(jss::credentials, "is non-empty array of CredentialID(hash256)"));
83 }
84 else if (creds.size() > maxCredentialsArraySize)
85 {
86 return RPC::make_error(rpcINVALID_PARAMS, RPC::expected_field_message(jss::credentials, "array too long"));
87 }
88
89 lifeExtender.reserve(creds.size());
90 for (auto const& jo : creds)
91 {
92 if (!jo.isString())
93 {
94 return RPC::make_error(
96 RPC::expected_field_message(jss::credentials, "an array of CredentialID(hash256)"));
97 }
98
99 uint256 credH;
100 auto const credS = jo.asString();
101 if (!credH.parseHex(credS))
102 {
103 return RPC::make_error(
105 RPC::expected_field_message(jss::credentials, "an array of CredentialID(hash256)"));
106 }
107
108 std::shared_ptr<SLE const> sleCred = ledger->read(keylet::credential(credH));
109 if (!sleCred)
110 {
111 RPC::inject_error(rpcBAD_CREDENTIALS, "credentials don't exist", result);
112 return result;
113 }
114
115 if (!(sleCred->getFlags() & lsfAccepted))
116 {
117 RPC::inject_error(rpcBAD_CREDENTIALS, "credentials aren't accepted", result);
118 return result;
119 }
120
121 if (credentials::checkExpired(sleCred, ledger->header().parentCloseTime))
122 {
123 RPC::inject_error(rpcBAD_CREDENTIALS, "credentials are expired", result);
124 return result;
125 }
126
127 if ((*sleCred)[sfSubject] != srcAcct)
128 {
129 RPC::inject_error(rpcBAD_CREDENTIALS, "credentials doesn't belong to the root account", result);
130 return result;
131 }
132
133 auto [it, ins] = sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]);
134 if (!ins)
135 {
136 RPC::inject_error(rpcBAD_CREDENTIALS, "duplicates in credentials", result);
137 return result;
138 }
139 lifeExtender.push_back(std::move(sleCred));
140 }
141 }
142
143 // If the two accounts are the same OR if that flag is
144 // not set, then the deposit should be fine.
145 bool depositAuthorized = true;
146 if (reqAuth)
147 depositAuthorized = ledger->exists(keylet::depositPreauth(dstAcct, srcAcct)) ||
148 (credentialsPresent && ledger->exists(keylet::depositPreauth(dstAcct, sorted)));
149
150 result[jss::source_account] = params[jss::source_account].asString();
151 result[jss::destination_account] = params[jss::destination_account].asString();
152 if (credentialsPresent)
153 result[jss::credentials] = params[jss::credentials];
154
155 result[jss::deposit_authorized] = depositAuthorized;
156 return result;
157}
158
159} // 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:471
T emplace(T... args)
std::string expected_field_message(std::string const &name, std::string const &type)
Definition ErrorCodes.h:280
Json::Value missing_field_error(std::string const &name)
Definition ErrorCodes.h:226
void inject_error(error_code_i code, Json::Value &json)
Add or update the json update to reflect the error code.
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 make_error(error_code_i code)
Returns a new json object that reflects the error code.
bool checkExpired(std::shared_ptr< SLE const > const &sleCredential, NetClock::time_point const &closed)
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition Indexes.cpp:299
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:160
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition Indexes.cpp:486
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Json::Value doDepositAuthorized(RPC::JsonContext &context)
std::size_t constexpr maxCredentialsArraySize
The maximum number of credentials can be passed in array.
Definition Protocol.h:223
Json::Value rpcError(error_code_i iError)
Definition RPCErr.cpp:12
@ lsfDepositAuth
@ lsfAccepted
@ rpcBAD_CREDENTIALS
Definition ErrorCodes.h:132
@ rpcSRC_ACT_NOT_FOUND
Definition ErrorCodes.h:102
@ rpcDST_ACT_NOT_FOUND
Definition ErrorCodes.h:85
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:64
@ rpcACT_MALFORMED
Definition ErrorCodes.h:70
T push_back(T... args)
T reserve(T... args)
Json::Value params
Definition Context.h:43