From 448267f6f0ce37c48257057e7ed8d5bb5558ec1d Mon Sep 17 00:00:00 2001 From: bthomee Date: Thu, 3 Jul 2025 14:31:52 +0000 Subject: [PATCH] deploy: 9874d47d7fbfe81e4cd78afd5b60ec33124ee2e9 --- CredentialHelpers_8cpp_source.html | 513 +++--- CredentialHelpers_8h_source.html | 193 ++- DeleteAccount_8cpp_source.html | 766 ++++----- DeleteAccount_8h_source.html | 6 +- DepositPreauth_8cpp_source.html | 4 +- Escrow_8cpp_source.html | 1475 +++++++++-------- Escrow_8h_source.html | 12 +- GatewayBalances_8cpp_source.html | 12 +- InvariantCheck_8cpp_source.html | 2 +- LedgerEntry_8cpp_source.html | 18 +- LedgerHistory_8cpp_source.html | 10 +- LedgerHistory_8h_source.html | 4 +- LedgerMaster_8cpp_source.html | 10 +- NetworkOPs_8cpp_source.html | 8 +- PathRequest_8cpp_source.html | 12 +- PathRequests_8cpp_source.html | 14 +- PayChan_8cpp_source.html | 265 +-- Payment_8cpp_source.html | 868 +++++----- Payment_8h_source.html | 6 +- PeerImp_8cpp_source.html | 6 +- PermissionedDomainSet_8cpp_source.html | 4 +- STAmount_8cpp_source.html | 6 +- StrandFlow_8h_source.html | 8 +- TaggedCache_8h_source.html | 4 +- ValidatorSite_8cpp_source.html | 14 +- VaultDeposit_8cpp_source.html | 2 +- View_8cpp_source.html | 2 +- apply__test_8cpp_source.html | 10 +- classripple_1_1DeleteAccount.html | 6 +- classripple_1_1EscrowCancel.html | 6 +- classripple_1_1EscrowFinish.html | 6 +- classripple_1_1LedgerHistory.html | 2 +- classripple_1_1PayChanClaim.html | 4 +- classripple_1_1Payment.html | 6 +- classripple_1_1TaggedCache.html | 2 +- namespacemembers_c.html | 2 +- namespacemembers_func_c.html | 2 +- namespacemembers_func_v.html | 4 +- namespacemembers_v.html | 4 +- namespaceripple.html | 44 +- namespaceripple_1_1credentials.html | 56 +- search/all_17.js | 4 +- search/all_4.js | 2 +- search/functions_16.js | 4 +- search/functions_3.js | 2 +- ...d_2app_2tx_2detail_2PayChan_8h_source.html | 4 +- 46 files changed, 2243 insertions(+), 2171 deletions(-) diff --git a/CredentialHelpers_8cpp_source.html b/CredentialHelpers_8cpp_source.html index bf6a6697bb..4fc5528f4a 100644 --- a/CredentialHelpers_8cpp_source.html +++ b/CredentialHelpers_8cpp_source.html @@ -198,15 +198,15 @@ $(function() {
120}
121
122NotTEC
-
123checkFields(PreflightContext const& ctx)
+
123checkFields(STTx const& tx, beast::Journal j)
124{
-
125 if (!ctx.tx.isFieldPresent(sfCredentialIDs))
+
125 if (!tx.isFieldPresent(sfCredentialIDs))
126 return tesSUCCESS;
127
-
128 auto const& credentials = ctx.tx.getFieldV256(sfCredentialIDs);
+
128 auto const& credentials = tx.getFieldV256(sfCredentialIDs);
129 if (credentials.empty() || (credentials.size() > maxCredentialsArraySize))
130 {
-
131 JLOG(ctx.j.trace())
+
131 JLOG(j.trace())
132 << "Malformed transaction: Credentials array size is invalid: "
133 << credentials.size();
134 return temMALFORMED;
@@ -218,7 +218,7 @@ $(function() {
140 auto [it, ins] = duplicates.insert(cred);
141 if (!ins)
142 {
-
143 JLOG(ctx.j.trace())
+
143 JLOG(j.trace())
144 << "Malformed transaction: duplicates in credentials.";
145 return temMALFORMED;
146 }
@@ -228,251 +228,250 @@ $(function() {
150}
151
152TER
-
153valid(PreclaimContext const& ctx, AccountID const& src)
-
154{
-
155 if (!ctx.tx.isFieldPresent(sfCredentialIDs))
-
156 return tesSUCCESS;
-
157
-
158 auto const& credIDs(ctx.tx.getFieldV256(sfCredentialIDs));
-
159 for (auto const& h : credIDs)
-
160 {
-
161 auto const sleCred = ctx.view.read(keylet::credential(h));
-
162 if (!sleCred)
-
163 {
-
164 JLOG(ctx.j.trace()) << "Credential doesn't exist. Cred: " << h;
-
165 return tecBAD_CREDENTIALS;
-
166 }
-
167
-
168 if (sleCred->getAccountID(sfSubject) != src)
-
169 {
-
170 JLOG(ctx.j.trace())
-
171 << "Credential doesn't belong to the source account. Cred: "
-
172 << h;
-
173 return tecBAD_CREDENTIALS;
-
174 }
-
175
-
176 if (!(sleCred->getFlags() & lsfAccepted))
-
177 {
-
178 JLOG(ctx.j.trace()) << "Credential isn't accepted. Cred: " << h;
-
179 return tecBAD_CREDENTIALS;
-
180 }
-
181
-
182 // Expiration checks are in doApply
-
183 }
-
184
-
185 return tesSUCCESS;
-
186}
-
187
-
188TER
-
189validDomain(ReadView const& view, uint256 domainID, AccountID const& subject)
-
190{
-
191 // Note, permissioned domain objects can be deleted at any time
-
192 auto const slePD = view.read(keylet::permissionedDomain(domainID));
-
193 if (!slePD)
-
194 return tecOBJECT_NOT_FOUND;
-
195
-
196 auto const closeTime = view.info().parentCloseTime;
-
197 bool foundExpired = false;
-
198 for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
-
199 {
-
200 auto const issuer = h.getAccountID(sfIssuer);
-
201 auto const type = h.getFieldVL(sfCredentialType);
-
202 auto const keyletCredential =
-
203 keylet::credential(subject, issuer, makeSlice(type));
-
204 auto const sleCredential = view.read(keyletCredential);
-
205
-
206 // We cannot delete expired credentials, that would require ApplyView&
-
207 // However we can check if credentials are expired. Expected transaction
-
208 // flow is to use `validDomain` in preclaim, converting tecEXPIRED to
-
209 // tesSUCCESS, then proceed to call `verifyValidDomain` in doApply. This
-
210 // allows expired credentials to be deleted by any transaction.
-
211 if (sleCredential)
-
212 {
-
213 if (checkExpired(sleCredential, closeTime))
-
214 {
-
215 foundExpired = true;
-
216 continue;
-
217 }
-
218 else if (sleCredential->getFlags() & lsfAccepted)
-
219 return tesSUCCESS;
-
220 else
-
221 continue;
-
222 }
-
223 }
-
224
-
225 return foundExpired ? tecEXPIRED : tecNO_AUTH;
-
226}
-
227
-
228TER
-
229authorizedDepositPreauth(
-
230 ApplyView const& view,
-
231 STVector256 const& credIDs,
-
232 AccountID const& dst)
-
233{
-
234 std::set<std::pair<AccountID, Slice>> sorted;
-
235 std::vector<std::shared_ptr<SLE const>> lifeExtender;
-
236 lifeExtender.reserve(credIDs.size());
-
237 for (auto const& h : credIDs)
-
238 {
-
239 auto sleCred = view.read(keylet::credential(h));
-
240 if (!sleCred) // already checked in preclaim
-
241 return tefINTERNAL; // LCOV_EXCL_LINE
-
242
-
243 auto [it, ins] =
-
244 sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]);
-
245 if (!ins)
-
246 return tefINTERNAL; // LCOV_EXCL_LINE
-
247 lifeExtender.push_back(std::move(sleCred));
-
248 }
-
249
-
250 if (!view.exists(keylet::depositPreauth(dst, sorted)))
-
251 return tecNO_PERMISSION;
-
252
-
253 return tesSUCCESS;
-
254}
-
255
-
256std::set<std::pair<AccountID, Slice>>
-
257makeSorted(STArray const& credentials)
-
258{
-
259 std::set<std::pair<AccountID, Slice>> out;
-
260 for (auto const& cred : credentials)
-
261 {
-
262 auto [it, ins] = out.emplace(cred[sfIssuer], cred[sfCredentialType]);
-
263 if (!ins)
-
264 return {};
-
265 }
-
266 return out;
-
267}
-
268
-
269NotTEC
-
270checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j)
-
271{
-
272 if (credentials.empty() || (credentials.size() > maxSize))
-
273 {
-
274 JLOG(j.trace()) << "Malformed transaction: "
-
275 "Invalid credentials size: "
-
276 << credentials.size();
-
277 return credentials.empty() ? temARRAY_EMPTY : temARRAY_TOO_LARGE;
-
278 }
-
279
-
280 std::unordered_set<uint256> duplicates;
-
281 for (auto const& credential : credentials)
-
282 {
-
283 auto const& issuer = credential[sfIssuer];
-
284 if (!issuer)
-
285 {
-
286 JLOG(j.trace()) << "Malformed transaction: "
-
287 "Issuer account is invalid: "
-
288 << to_string(issuer);
-
289 return temINVALID_ACCOUNT_ID;
-
290 }
-
291
-
292 auto const ct = credential[sfCredentialType];
-
293 if (ct.empty() || (ct.size() > maxCredentialTypeLength))
-
294 {
-
295 JLOG(j.trace()) << "Malformed transaction: "
-
296 "Invalid credentialType size: "
-
297 << ct.size();
-
298 return temMALFORMED;
-
299 }
-
300
-
301 auto [it, ins] = duplicates.insert(sha512Half(issuer, ct));
-
302 if (!ins)
-
303 {
-
304 JLOG(j.trace()) << "Malformed transaction: "
-
305 "duplicates in credenentials.";
-
306 return temMALFORMED;
-
307 }
-
308 }
-
309
-
310 return tesSUCCESS;
-
311}
-
312
-
313} // namespace credentials
-
314
-
315TER
-
316verifyValidDomain(
-
317 ApplyView& view,
-
318 AccountID const& account,
-
319 uint256 domainID,
-
320 beast::Journal j)
-
321{
-
322 auto const slePD = view.read(keylet::permissionedDomain(domainID));
-
323 if (!slePD)
-
324 return tecOBJECT_NOT_FOUND;
-
325
-
326 // Collect all matching credentials on a side, so we can remove expired ones
-
327 // We may finish the loop with this collection empty, it's fine.
-
328 STVector256 credentials;
-
329 for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
-
330 {
-
331 auto const issuer = h.getAccountID(sfIssuer);
-
332 auto const type = h.getFieldVL(sfCredentialType);
-
333 auto const keyletCredential =
-
334 keylet::credential(account, issuer, makeSlice(type));
-
335 if (view.exists(keyletCredential))
-
336 credentials.push_back(keyletCredential.key);
-
337 }
-
338
-
339 bool const foundExpired = credentials::removeExpired(view, credentials, j);
-
340 for (auto const& h : credentials)
-
341 {
-
342 auto sleCredential = view.read(keylet::credential(h));
-
343 if (!sleCredential)
-
344 continue; // expired, i.e. deleted in credentials::removeExpired
-
345
-
346 if (sleCredential->getFlags() & lsfAccepted)
-
347 return tesSUCCESS;
-
348 }
+
153valid(
+
154 STTx const& tx,
+
155 ReadView const& view,
+
156 AccountID const& src,
+
157 beast::Journal j)
+
158{
+
159 if (!tx.isFieldPresent(sfCredentialIDs))
+
160 return tesSUCCESS;
+
161
+
162 auto const& credIDs(tx.getFieldV256(sfCredentialIDs));
+
163 for (auto const& h : credIDs)
+
164 {
+
165 auto const sleCred = view.read(keylet::credential(h));
+
166 if (!sleCred)
+
167 {
+
168 JLOG(j.trace()) << "Credential doesn't exist. Cred: " << h;
+
169 return tecBAD_CREDENTIALS;
+
170 }
+
171
+
172 if (sleCred->getAccountID(sfSubject) != src)
+
173 {
+
174 JLOG(j.trace())
+
175 << "Credential doesn't belong to the source account. Cred: "
+
176 << h;
+
177 return tecBAD_CREDENTIALS;
+
178 }
+
179
+
180 if (!(sleCred->getFlags() & lsfAccepted))
+
181 {
+
182 JLOG(j.trace()) << "Credential isn't accepted. Cred: " << h;
+
183 return tecBAD_CREDENTIALS;
+
184 }
+
185
+
186 // Expiration checks are in doApply
+
187 }
+
188
+
189 return tesSUCCESS;
+
190}
+
191
+
192TER
+
193validDomain(ReadView const& view, uint256 domainID, AccountID const& subject)
+
194{
+
195 // Note, permissioned domain objects can be deleted at any time
+
196 auto const slePD = view.read(keylet::permissionedDomain(domainID));
+
197 if (!slePD)
+
198 return tecOBJECT_NOT_FOUND;
+
199
+
200 auto const closeTime = view.info().parentCloseTime;
+
201 bool foundExpired = false;
+
202 for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
+
203 {
+
204 auto const issuer = h.getAccountID(sfIssuer);
+
205 auto const type = h.getFieldVL(sfCredentialType);
+
206 auto const keyletCredential =
+
207 keylet::credential(subject, issuer, makeSlice(type));
+
208 auto const sleCredential = view.read(keyletCredential);
+
209
+
210 // We cannot delete expired credentials, that would require ApplyView&
+
211 // However we can check if credentials are expired. Expected transaction
+
212 // flow is to use `validDomain` in preclaim, converting tecEXPIRED to
+
213 // tesSUCCESS, then proceed to call `verifyValidDomain` in doApply. This
+
214 // allows expired credentials to be deleted by any transaction.
+
215 if (sleCredential)
+
216 {
+
217 if (checkExpired(sleCredential, closeTime))
+
218 {
+
219 foundExpired = true;
+
220 continue;
+
221 }
+
222 else if (sleCredential->getFlags() & lsfAccepted)
+
223 return tesSUCCESS;
+
224 else
+
225 continue;
+
226 }
+
227 }
+
228
+
229 return foundExpired ? tecEXPIRED : tecNO_AUTH;
+
230}
+
231
+
232TER
+
233authorizedDepositPreauth(
+
234 ApplyView const& view,
+
235 STVector256 const& credIDs,
+
236 AccountID const& dst)
+
237{
+
238 std::set<std::pair<AccountID, Slice>> sorted;
+
239 std::vector<std::shared_ptr<SLE const>> lifeExtender;
+
240 lifeExtender.reserve(credIDs.size());
+
241 for (auto const& h : credIDs)
+
242 {
+
243 auto sleCred = view.read(keylet::credential(h));
+
244 if (!sleCred) // already checked in preclaim
+
245 return tefINTERNAL; // LCOV_EXCL_LINE
+
246
+
247 auto [it, ins] =
+
248 sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]);
+
249 if (!ins)
+
250 return tefINTERNAL; // LCOV_EXCL_LINE
+
251 lifeExtender.push_back(std::move(sleCred));
+
252 }
+
253
+
254 if (!view.exists(keylet::depositPreauth(dst, sorted)))
+
255 return tecNO_PERMISSION;
+
256
+
257 return tesSUCCESS;
+
258}
+
259
+
260std::set<std::pair<AccountID, Slice>>
+
261makeSorted(STArray const& credentials)
+
262{
+
263 std::set<std::pair<AccountID, Slice>> out;
+
264 for (auto const& cred : credentials)
+
265 {
+
266 auto [it, ins] = out.emplace(cred[sfIssuer], cred[sfCredentialType]);
+
267 if (!ins)
+
268 return {};
+
269 }
+
270 return out;
+
271}
+
272
+
273NotTEC
+
274checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j)
+
275{
+
276 if (credentials.empty() || (credentials.size() > maxSize))
+
277 {
+
278 JLOG(j.trace()) << "Malformed transaction: "
+
279 "Invalid credentials size: "
+
280 << credentials.size();
+
281 return credentials.empty() ? temARRAY_EMPTY : temARRAY_TOO_LARGE;
+
282 }
+
283
+
284 std::unordered_set<uint256> duplicates;
+
285 for (auto const& credential : credentials)
+
286 {
+
287 auto const& issuer = credential[sfIssuer];
+
288 if (!issuer)
+
289 {
+
290 JLOG(j.trace()) << "Malformed transaction: "
+
291 "Issuer account is invalid: "
+
292 << to_string(issuer);
+
293 return temINVALID_ACCOUNT_ID;
+
294 }
+
295
+
296 auto const ct = credential[sfCredentialType];
+
297 if (ct.empty() || (ct.size() > maxCredentialTypeLength))
+
298 {
+
299 JLOG(j.trace()) << "Malformed transaction: "
+
300 "Invalid credentialType size: "
+
301 << ct.size();
+
302 return temMALFORMED;
+
303 }
+
304
+
305 auto [it, ins] = duplicates.insert(sha512Half(issuer, ct));
+
306 if (!ins)
+
307 {
+
308 JLOG(j.trace()) << "Malformed transaction: "
+
309 "duplicates in credenentials.";
+
310 return temMALFORMED;
+
311 }
+
312 }
+
313
+
314 return tesSUCCESS;
+
315}
+
316
+
317} // namespace credentials
+
318
+
319TER
+
320verifyValidDomain(
+
321 ApplyView& view,
+
322 AccountID const& account,
+
323 uint256 domainID,
+
324 beast::Journal j)
+
325{
+
326 auto const slePD = view.read(keylet::permissionedDomain(domainID));
+
327 if (!slePD)
+
328 return tecOBJECT_NOT_FOUND;
+
329
+
330 // Collect all matching credentials on a side, so we can remove expired ones
+
331 // We may finish the loop with this collection empty, it's fine.
+
332 STVector256 credentials;
+
333 for (auto const& h : slePD->getFieldArray(sfAcceptedCredentials))
+
334 {
+
335 auto const issuer = h.getAccountID(sfIssuer);
+
336 auto const type = h.getFieldVL(sfCredentialType);
+
337 auto const keyletCredential =
+
338 keylet::credential(account, issuer, makeSlice(type));
+
339 if (view.exists(keyletCredential))
+
340 credentials.push_back(keyletCredential.key);
+
341 }
+
342
+
343 bool const foundExpired = credentials::removeExpired(view, credentials, j);
+
344 for (auto const& h : credentials)
+
345 {
+
346 auto sleCredential = view.read(keylet::credential(h));
+
347 if (!sleCredential)
+
348 continue; // expired, i.e. deleted in credentials::removeExpired
349
-
350 return foundExpired ? tecEXPIRED : tecNO_PERMISSION;
-
351}
-
352
-
353TER
-
354verifyDepositPreauth(
-
355 ApplyContext& ctx,
-
356 AccountID const& src,
-
357 AccountID const& dst,
-
358 std::shared_ptr<SLE> const& sleDst)
-
359{
-
360 // If depositPreauth is enabled, then an account that requires
-
361 // authorization has at least two ways to get a payment in:
-
362 // 1. If src == dst, or
-
363 // 2. If src is deposit preauthorized by dst (either by account or by
-
364 // credentials).
-
365
-
366 bool const credentialsPresent = ctx.tx.isFieldPresent(sfCredentialIDs);
-
367
-
368 if (credentialsPresent &&
-
369 credentials::removeExpired(
-
370 ctx.view(), ctx.tx.getFieldV256(sfCredentialIDs), ctx.journal))
-
371 return tecEXPIRED;
-
372
-
373 if (sleDst && (sleDst->getFlags() & lsfDepositAuth))
-
374 {
-
375 if (src != dst)
-
376 {
-
377 if (!ctx.view().exists(keylet::depositPreauth(dst, src)))
-
378 return !credentialsPresent
-
379 ? tecNO_PERMISSION
-
380 : credentials::authorizedDepositPreauth(
-
381 ctx.view(),
-
382 ctx.tx.getFieldV256(sfCredentialIDs),
-
383 dst);
-
384 }
-
385 }
-
386
-
387 return tesSUCCESS;
-
388}
+
350 if (sleCredential->getFlags() & lsfAccepted)
+
351 return tesSUCCESS;
+
352 }
+
353
+
354 return foundExpired ? tecEXPIRED : tecNO_PERMISSION;
+
355}
+
356
+
357TER
+
358verifyDepositPreauth(
+
359 STTx const& tx,
+
360 ApplyView& view,
+
361 AccountID const& src,
+
362 AccountID const& dst,
+
363 std::shared_ptr<SLE> const& sleDst,
+
364 beast::Journal j)
+
365{
+
366 // If depositPreauth is enabled, then an account that requires
+
367 // authorization has at least two ways to get a payment in:
+
368 // 1. If src == dst, or
+
369 // 2. If src is deposit preauthorized by dst (either by account or by
+
370 // credentials).
+
371
+
372 bool const credentialsPresent = tx.isFieldPresent(sfCredentialIDs);
+
373
+
374 if (credentialsPresent &&
+
375 credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j))
+
376 return tecEXPIRED;
+
377
+
378 if (sleDst && (sleDst->getFlags() & lsfDepositAuth))
+
379 {
+
380 if (src != dst)
+
381 {
+
382 if (!view.exists(keylet::depositPreauth(dst, src)))
+
383 return !credentialsPresent
+
384 ? tecNO_PERMISSION
+
385 : credentials::authorizedDepositPreauth(
+
386 view, tx.getFieldV256(sfCredentialIDs), dst);
+
387 }
+
388 }
389
-
390} // namespace ripple
+
390 return tesSUCCESS;
+
391}
+
392
+
393} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream fatal() const
Definition: Journal.h:352
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
-
State information when applying a tx.
Definition: ApplyContext.h:37
-
ApplyView & view()
Definition: ApplyContext.h:78
-
beast::Journal const journal
Definition: ApplyContext.h:75
-
STTx const & tx
Definition: ApplyContext.h:72
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:144
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:190
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
@@ -487,6 +486,7 @@ $(function() {
size_type size() const
Definition: STArray.h:248
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:484
STVector256 const & getFieldV256(SField const &field) const
Definition: STObject.cpp:679
+
Definition: STTx.h:48
Definition: STVector256.h:31
std::size_t size() const
Definition: STVector256.h:168
void push_back(uint256 const &v)
Definition: STVector256.h:218
@@ -495,15 +495,15 @@ $(function() {
T emplace(T... args)
T insert(T... args)
-
NotTEC checkFields(PreflightContext const &ctx)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER deleteSLE(ApplyView &view, std::shared_ptr< SLE > const &sleCredential, beast::Journal j)
bool removeExpired(ApplyView &view, STVector256 const &arr, beast::Journal const j)
-
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
-
TER authorizedDepositPreauth(ApplyView const &view, STVector256 const &credIDs, AccountID const &dst)
-
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
+
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
+
TER authorizedDepositPreauth(ApplyView const &view, STVector256 const &credIDs, AccountID const &dst)
+
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
bool checkExpired(std::shared_ptr< SLE const > const &sleCredential, NetClock::time_point const &closed)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition: Indexes.cpp:570
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
Definition: Indexes.cpp:553
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
@@ -512,6 +512,7 @@ $(function() {
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ lsfDepositAuth
@ lsfAccepted
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
@ tefBAD_LEDGER
Definition: TER.h:170
@ tefINTERNAL
Definition: TER.h:173
@ out
@@ -528,10 +529,9 @@ $(function() {
@ tecEXPIRED
Definition: TER.h:314
@ tecNO_AUTH
Definition: TER.h:300
@ tesSUCCESS
Definition: TER.h:244
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
-
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
+
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
@ credential
Credentials signature.
TERSubset< CanCvtToTER > TER
Definition: TER.h:645
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:225
@@ -545,13 +545,6 @@ $(function() {
NetClock::time_point parentCloseTime
Definition: LedgerHeader.h:42
-
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:79
-
ReadView const & view
Definition: Transactor.h:82
-
STTx const & tx
Definition: Transactor.h:85
-
beast::Journal const j
Definition: Transactor.h:87
-
State information when preflighting a tx.
Definition: Transactor.h:34
-
beast::Journal const j
Definition: Transactor.h:41
-
STTx const & tx
Definition: Transactor.h:37
T time_since_epoch(T... args)
diff --git a/CredentialHelpers_8h_source.html b/CredentialHelpers_8h_source.html index 71d9b6e1f1..26e6c91f1d 100644 --- a/CredentialHelpers_8h_source.html +++ b/CredentialHelpers_8h_source.html @@ -98,103 +98,118 @@ $(function() {
20#ifndef RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED
21#define RIPPLE_APP_MISC_CREDENTIALHELPERS_H_INCLUDED
22
-
23#include <xrpld/app/tx/detail/Transactor.h>
-
24
-
25namespace ripple {
-
26namespace credentials {
-
27
-
28// These function will be used by the code that use DepositPreauth / Credentials
-
29// (and any future preauthorization modes) as part of authorization (all the
-
30// transfer funds transactions)
-
31
-
32// Check if credential sfExpiration field has passed ledger's parentCloseTime
-
33bool
-
34checkExpired(
-
35 std::shared_ptr<SLE const> const& sleCredential,
-
36 NetClock::time_point const& closed);
-
37
-
38// Return true if any expired credential was found in arr (and deleted)
-
39bool
-
40removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j);
-
41
-
42// Actually remove a credentials object from the ledger
-
43TER
-
44deleteSLE(
-
45 ApplyView& view,
-
46 std::shared_ptr<SLE> const& sleCredential,
-
47 beast::Journal j);
-
48
-
49// Amendment and parameters checks for sfCredentialIDs field
-
50NotTEC
-
51checkFields(PreflightContext const& ctx);
-
52
-
53// Accessing the ledger to check if provided credentials are valid. Do not use
-
54// in doApply (only in preclaim) since it does not remove expired credentials.
-
55// If you call it in prelaim, you also must call verifyDepositPreauth in doApply
-
56TER
-
57valid(PreclaimContext const& ctx, AccountID const& src);
-
58
-
59// Check if subject has any credential maching the given domain. If you call it
-
60// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
-
61// doApply. This will ensure that expired credentials are deleted.
-
62TER
-
63validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
-
64
-
65// This function is only called when we about to return tecNO_PERMISSION
-
66// because all the checks for the DepositPreauth authorization failed.
-
67TER
-
68authorizedDepositPreauth(
-
69 ApplyView const& view,
-
70 STVector256 const& ctx,
-
71 AccountID const& dst);
-
72
-
73// Sort credentials array, return empty set if there are duplicates
-
74std::set<std::pair<AccountID, Slice>>
-
75makeSorted(STArray const& credentials);
-
76
-
77// Check credentials array passed to DepositPreauth/PermissionedDomainSet
-
78// transactions
-
79NotTEC
-
80checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
-
81
-
82} // namespace credentials
-
83
-
84// Check expired credentials and for credentials maching DomainID of the ledger
-
85// object
-
86TER
-
87verifyValidDomain(
-
88 ApplyView& view,
-
89 AccountID const& account,
-
90 uint256 domainID,
-
91 beast::Journal j);
-
92
-
93// Check expired credentials and for existing DepositPreauth ledger object
-
94TER
-
95verifyDepositPreauth(
-
96 ApplyContext& ctx,
-
97 AccountID const& src,
-
98 AccountID const& dst,
-
99 std::shared_ptr<SLE> const& sleDst);
-
100
-
101} // namespace ripple
-
102
-
103#endif
+
23#include <xrpld/ledger/ApplyView.h>
+
24#include <xrpld/ledger/ReadView.h>
+
25
+
26#include <xrpl/basics/Log.h>
+
27#include <xrpl/basics/base_uint.h>
+
28#include <xrpl/beast/utility/Journal.h>
+
29#include <xrpl/protocol/AccountID.h>
+
30#include <xrpl/protocol/STArray.h>
+
31#include <xrpl/protocol/STTx.h>
+
32#include <xrpl/protocol/TER.h>
+
33
+
34namespace ripple {
+
35namespace credentials {
+
36
+
37// These function will be used by the code that use DepositPreauth / Credentials
+
38// (and any future preauthorization modes) as part of authorization (all the
+
39// transfer funds transactions)
+
40
+
41// Check if credential sfExpiration field has passed ledger's parentCloseTime
+
42bool
+
43checkExpired(
+
44 std::shared_ptr<SLE const> const& sleCredential,
+
45 NetClock::time_point const& closed);
+
46
+
47// Return true if any expired credential was found in arr (and deleted)
+
48bool
+
49removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j);
+
50
+
51// Actually remove a credentials object from the ledger
+
52TER
+
53deleteSLE(
+
54 ApplyView& view,
+
55 std::shared_ptr<SLE> const& sleCredential,
+
56 beast::Journal j);
+
57
+
58// Amendment and parameters checks for sfCredentialIDs field
+
59NotTEC
+
60checkFields(STTx const& tx, beast::Journal j);
+
61
+
62// Accessing the ledger to check if provided credentials are valid. Do not use
+
63// in doApply (only in preclaim) since it does not remove expired credentials.
+
64// If you call it in prelaim, you also must call verifyDepositPreauth in doApply
+
65TER
+
66valid(
+
67 STTx const& tx,
+
68 ReadView const& view,
+
69 AccountID const& src,
+
70 beast::Journal j);
+
71
+
72// Check if subject has any credential maching the given domain. If you call it
+
73// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
+
74// doApply. This will ensure that expired credentials are deleted.
+
75TER
+
76validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
+
77
+
78// This function is only called when we about to return tecNO_PERMISSION
+
79// because all the checks for the DepositPreauth authorization failed.
+
80TER
+
81authorizedDepositPreauth(
+
82 ApplyView const& view,
+
83 STVector256 const& ctx,
+
84 AccountID const& dst);
+
85
+
86// Sort credentials array, return empty set if there are duplicates
+
87std::set<std::pair<AccountID, Slice>>
+
88makeSorted(STArray const& credentials);
+
89
+
90// Check credentials array passed to DepositPreauth/PermissionedDomainSet
+
91// transactions
+
92NotTEC
+
93checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
+
94
+
95} // namespace credentials
+
96
+
97// Check expired credentials and for credentials maching DomainID of the ledger
+
98// object
+
99TER
+
100verifyValidDomain(
+
101 ApplyView& view,
+
102 AccountID const& account,
+
103 uint256 domainID,
+
104 beast::Journal j);
+
105
+
106// Check expired credentials and for existing DepositPreauth ledger object
+
107TER
+
108verifyDepositPreauth(
+
109 STTx const& tx,
+
110 ApplyView& view,
+
111 AccountID const& src,
+
112 AccountID const& dst,
+
113 std::shared_ptr<SLE> const& sleDst,
+
114 beast::Journal j);
+
115
+
116} // namespace ripple
+
117
+
118#endif
A generic endpoint for log messages.
Definition: Journal.h:60
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:69
-
NotTEC checkFields(PreflightContext const &ctx)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER deleteSLE(ApplyView &view, std::shared_ptr< SLE > const &sleCredential, beast::Journal j)
bool removeExpired(ApplyView &view, STVector256 const &arr, beast::Journal const j)
-
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
-
TER authorizedDepositPreauth(ApplyView const &view, STVector256 const &credIDs, AccountID const &dst)
-
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
+
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
+
TER authorizedDepositPreauth(ApplyView const &view, STVector256 const &credIDs, AccountID const &dst)
+
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
bool checkExpired(std::shared_ptr< SLE const > const &sleCredential, NetClock::time_point const &closed)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:49
base_uint< 256 > uint256
Definition: base_uint.h:558
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
-
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
+
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
TERSubset< CanCvtToTER > TER
Definition: TER.h:645
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:605
diff --git a/DeleteAccount_8cpp_source.html b/DeleteAccount_8cpp_source.html index 2f914fede9..c65fe52413 100644 --- a/DeleteAccount_8cpp_source.html +++ b/DeleteAccount_8cpp_source.html @@ -136,384 +136,387 @@ $(function() {
58 // An account cannot be deleted and give itself the resulting XRP.
59 return temDST_IS_SRC;
60
-
61 if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err))
-
62 return err;
-
63
-
64 return preflight2(ctx);
-
65}
-
66
-
67XRPAmount
-
68DeleteAccount::calculateBaseFee(ReadView const& view, STTx const& tx)
-
69{
-
70 // The fee required for AccountDelete is one owner reserve.
-
71 return view.fees().increment;
-
72}
-
73
-
74namespace {
-
75// Define a function pointer type that can be used to delete ledger node types.
-
76using DeleterFuncPtr = TER (*)(
-
77 Application& app,
-
78 ApplyView& view,
-
79 AccountID const& account,
-
80 uint256 const& delIndex,
-
81 std::shared_ptr<SLE> const& sleDel,
-
82 beast::Journal j);
-
83
-
84// Local function definitions that provides signature compatibility.
-
85TER
-
86offerDelete(
-
87 Application& app,
-
88 ApplyView& view,
-
89 AccountID const& account,
-
90 uint256 const& delIndex,
-
91 std::shared_ptr<SLE> const& sleDel,
-
92 beast::Journal j)
-
93{
-
94 return offerDelete(view, sleDel, j);
-
95}
-
96
-
97TER
-
98removeSignersFromLedger(
-
99 Application& app,
-
100 ApplyView& view,
-
101 AccountID const& account,
-
102 uint256 const& delIndex,
-
103 std::shared_ptr<SLE> const& sleDel,
-
104 beast::Journal j)
-
105{
-
106 return SetSignerList::removeFromLedger(app, view, account, j);
-
107}
-
108
-
109TER
-
110removeTicketFromLedger(
-
111 Application&,
-
112 ApplyView& view,
-
113 AccountID const& account,
-
114 uint256 const& delIndex,
-
115 std::shared_ptr<SLE> const&,
-
116 beast::Journal j)
-
117{
-
118 return Transactor::ticketDelete(view, account, delIndex, j);
-
119}
-
120
-
121TER
-
122removeDepositPreauthFromLedger(
-
123 Application&,
-
124 ApplyView& view,
-
125 AccountID const&,
-
126 uint256 const& delIndex,
-
127 std::shared_ptr<SLE> const&,
-
128 beast::Journal j)
-
129{
-
130 return DepositPreauth::removeFromLedger(view, delIndex, j);
-
131}
-
132
-
133TER
-
134removeNFTokenOfferFromLedger(
-
135 Application& app,
-
136 ApplyView& view,
-
137 AccountID const& account,
-
138 uint256 const& delIndex,
-
139 std::shared_ptr<SLE> const& sleDel,
-
140 beast::Journal)
-
141{
-
142 if (!nft::deleteTokenOffer(view, sleDel))
-
143 return tefBAD_LEDGER;
-
144
-
145 return tesSUCCESS;
-
146}
-
147
-
148TER
-
149removeDIDFromLedger(
-
150 Application& app,
-
151 ApplyView& view,
-
152 AccountID const& account,
-
153 uint256 const& delIndex,
-
154 std::shared_ptr<SLE> const& sleDel,
-
155 beast::Journal j)
-
156{
-
157 return DIDDelete::deleteSLE(view, sleDel, account, j);
-
158}
-
159
-
160TER
-
161removeOracleFromLedger(
-
162 Application&,
-
163 ApplyView& view,
-
164 AccountID const& account,
-
165 uint256 const&,
-
166 std::shared_ptr<SLE> const& sleDel,
-
167 beast::Journal j)
-
168{
-
169 return DeleteOracle::deleteOracle(view, sleDel, account, j);
-
170}
-
171
-
172TER
-
173removeCredentialFromLedger(
-
174 Application&,
-
175 ApplyView& view,
-
176 AccountID const&,
-
177 uint256 const&,
-
178 std::shared_ptr<SLE> const& sleDel,
-
179 beast::Journal j)
-
180{
-
181 return credentials::deleteSLE(view, sleDel, j);
-
182}
-
183
-
184TER
-
185removeDelegateFromLedger(
-
186 Application& app,
-
187 ApplyView& view,
-
188 AccountID const& account,
-
189 uint256 const& delIndex,
-
190 std::shared_ptr<SLE> const& sleDel,
-
191 beast::Journal j)
-
192{
-
193 return DelegateSet::deleteDelegate(view, sleDel, account, j);
-
194}
-
195
-
196// Return nullptr if the LedgerEntryType represents an obligation that can't
-
197// be deleted. Otherwise return the pointer to the function that can delete
-
198// the non-obligation
-
199DeleterFuncPtr
-
200nonObligationDeleter(LedgerEntryType t)
-
201{
-
202 switch (t)
-
203 {
-
204 case ltOFFER:
-
205 return offerDelete;
-
206 case ltSIGNER_LIST:
-
207 return removeSignersFromLedger;
-
208 case ltTICKET:
-
209 return removeTicketFromLedger;
-
210 case ltDEPOSIT_PREAUTH:
-
211 return removeDepositPreauthFromLedger;
-
212 case ltNFTOKEN_OFFER:
-
213 return removeNFTokenOfferFromLedger;
-
214 case ltDID:
-
215 return removeDIDFromLedger;
-
216 case ltORACLE:
-
217 return removeOracleFromLedger;
-
218 case ltCREDENTIAL:
-
219 return removeCredentialFromLedger;
-
220 case ltDELEGATE:
-
221 return removeDelegateFromLedger;
-
222 default:
-
223 return nullptr;
-
224 }
-
225}
-
226
-
227} // namespace
-
228
-
229TER
-
230DeleteAccount::preclaim(PreclaimContext const& ctx)
-
231{
-
232 AccountID const account{ctx.tx[sfAccount]};
-
233 AccountID const dst{ctx.tx[sfDestination]};
-
234
-
235 auto sleDst = ctx.view.read(keylet::account(dst));
-
236
-
237 if (!sleDst)
-
238 return tecNO_DST;
-
239
-
240 if ((*sleDst)[sfFlags] & lsfRequireDestTag && !ctx.tx[~sfDestinationTag])
-
241 return tecDST_TAG_NEEDED;
-
242
-
243 // If credentials are provided - check them anyway
-
244 if (auto const err = credentials::valid(ctx, account); !isTesSuccess(err))
-
245 return err;
-
246
-
247 // if credentials then postpone auth check to doApply, to check for expired
-
248 // credentials
-
249 if (!ctx.tx.isFieldPresent(sfCredentialIDs))
-
250 {
-
251 // Check whether the destination account requires deposit authorization.
-
252 if (ctx.view.rules().enabled(featureDepositAuth) &&
-
253 (sleDst->getFlags() & lsfDepositAuth))
-
254 {
-
255 if (!ctx.view.exists(keylet::depositPreauth(dst, account)))
-
256 return tecNO_PERMISSION;
-
257 }
-
258 }
-
259
-
260 auto sleAccount = ctx.view.read(keylet::account(account));
-
261 XRPL_ASSERT(
-
262 sleAccount, "ripple::DeleteAccount::preclaim : non-null account");
-
263 if (!sleAccount)
-
264 return terNO_ACCOUNT;
-
265
-
266 if (ctx.view.rules().enabled(featureNonFungibleTokensV1))
-
267 {
-
268 // If an issuer has any issued NFTs resident in the ledger then it
-
269 // cannot be deleted.
-
270 if ((*sleAccount)[~sfMintedNFTokens] !=
-
271 (*sleAccount)[~sfBurnedNFTokens])
-
272 return tecHAS_OBLIGATIONS;
-
273
-
274 // If the account owns any NFTs it cannot be deleted.
-
275 Keylet const first = keylet::nftpage_min(account);
-
276 Keylet const last = keylet::nftpage_max(account);
-
277
-
278 auto const cp = ctx.view.read(Keylet(
-
279 ltNFTOKEN_PAGE,
-
280 ctx.view.succ(first.key, last.key.next()).value_or(last.key)));
-
281 if (cp)
-
282 return tecHAS_OBLIGATIONS;
-
283 }
-
284
-
285 // We don't allow an account to be deleted if its sequence number
-
286 // is within 256 of the current ledger. This prevents replay of old
-
287 // transactions if this account is resurrected after it is deleted.
-
288 //
-
289 // We look at the account's Sequence rather than the transaction's
-
290 // Sequence in preparation for Tickets.
-
291 constexpr std::uint32_t seqDelta{255};
-
292 if ((*sleAccount)[sfSequence] + seqDelta > ctx.view.seq())
-
293 return tecTOO_SOON;
-
294
-
295 // When fixNFTokenRemint is enabled, we don't allow an account to be
-
296 // deleted if <FirstNFTokenSequence + MintedNFTokens> is within 256 of the
-
297 // current ledger. This is to prevent having duplicate NFTokenIDs after
-
298 // account re-creation.
-
299 //
-
300 // Without this restriction, duplicate NFTokenIDs can be reproduced when
-
301 // authorized minting is involved. Because when the minter mints a NFToken,
-
302 // the issuer's sequence does not change. So when the issuer re-creates
-
303 // their account and mints a NFToken, it is possible that the
-
304 // NFTokenSequence of this NFToken is the same as the one that the
-
305 // authorized minter minted in a previous ledger.
-
306 if (ctx.view.rules().enabled(fixNFTokenRemint) &&
-
307 ((*sleAccount)[~sfFirstNFTokenSequence].value_or(0) +
-
308 (*sleAccount)[~sfMintedNFTokens].value_or(0) + seqDelta >
-
309 ctx.view.seq()))
-
310 return tecTOO_SOON;
-
311
-
312 // Verify that the account does not own any objects that would prevent
-
313 // the account from being deleted.
-
314 Keylet const ownerDirKeylet{keylet::ownerDir(account)};
-
315 if (dirIsEmpty(ctx.view, ownerDirKeylet))
-
316 return tesSUCCESS;
-
317
-
318 std::shared_ptr<SLE const> sleDirNode{};
-
319 unsigned int uDirEntry{0};
-
320 uint256 dirEntry{beast::zero};
-
321
-
322 // Account has no directory at all. This _should_ have been caught
-
323 // by the dirIsEmpty() check earlier, but it's okay to catch it here.
-
324 if (!cdirFirst(
-
325 ctx.view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry))
-
326 return tesSUCCESS;
-
327
-
328 std::int32_t deletableDirEntryCount{0};
-
329 do
-
330 {
-
331 // Make sure any directory node types that we find are the kind
-
332 // we can delete.
-
333 auto sleItem = ctx.view.read(keylet::child(dirEntry));
-
334 if (!sleItem)
-
335 {
-
336 // Directory node has an invalid index. Bail out.
-
337 JLOG(ctx.j.fatal())
-
338 << "DeleteAccount: directory node in ledger " << ctx.view.seq()
-
339 << " has index to object that is missing: "
-
340 << to_string(dirEntry);
-
341 return tefBAD_LEDGER;
-
342 }
-
343
-
344 LedgerEntryType const nodeType{
-
345 safe_cast<LedgerEntryType>((*sleItem)[sfLedgerEntryType])};
-
346
-
347 if (!nonObligationDeleter(nodeType))
-
348 return tecHAS_OBLIGATIONS;
-
349
-
350 // We found a deletable directory entry. Count it. If we find too
-
351 // many deletable directory entries then bail out.
-
352 if (++deletableDirEntryCount > maxDeletableDirEntries)
-
353 return tefTOO_BIG;
-
354
-
355 } while (cdirNext(
-
356 ctx.view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry));
-
357
-
358 return tesSUCCESS;
-
359}
-
360
-
361TER
-
362DeleteAccount::doApply()
-
363{
-
364 auto src = view().peek(keylet::account(account_));
-
365 XRPL_ASSERT(
-
366 src, "ripple::DeleteAccount::doApply : non-null source account");
-
367
-
368 auto const dstID = ctx_.tx[sfDestination];
-
369 auto dst = view().peek(keylet::account(dstID));
-
370 XRPL_ASSERT(
-
371 dst, "ripple::DeleteAccount::doApply : non-null destination account");
-
372
-
373 if (!src || !dst)
-
374 return tefBAD_LEDGER;
-
375
-
376 if (ctx_.view().rules().enabled(featureDepositAuth) &&
-
377 ctx_.tx.isFieldPresent(sfCredentialIDs))
-
378 {
-
379 if (auto err = verifyDepositPreauth(ctx_, account_, dstID, dst);
-
380 !isTesSuccess(err))
-
381 return err;
-
382 }
-
383
-
384 Keylet const ownerDirKeylet{keylet::ownerDir(account_)};
-
385 auto const ter = cleanupOnAccountDelete(
-
386 view(),
-
387 ownerDirKeylet,
-
388 [&](LedgerEntryType nodeType,
-
389 uint256 const& dirEntry,
-
390 std::shared_ptr<SLE>& sleItem) -> std::pair<TER, SkipEntry> {
-
391 if (auto deleter = nonObligationDeleter(nodeType))
-
392 {
-
393 TER const result{
-
394 deleter(ctx_.app, view(), account_, dirEntry, sleItem, j_)};
-
395
-
396 return {result, SkipEntry::No};
-
397 }
+
61 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
+
62 !isTesSuccess(err))
+
63 return err;
+
64
+
65 return preflight2(ctx);
+
66}
+
67
+
68XRPAmount
+
69DeleteAccount::calculateBaseFee(ReadView const& view, STTx const& tx)
+
70{
+
71 // The fee required for AccountDelete is one owner reserve.
+
72 return view.fees().increment;
+
73}
+
74
+
75namespace {
+
76// Define a function pointer type that can be used to delete ledger node types.
+
77using DeleterFuncPtr = TER (*)(
+
78 Application& app,
+
79 ApplyView& view,
+
80 AccountID const& account,
+
81 uint256 const& delIndex,
+
82 std::shared_ptr<SLE> const& sleDel,
+
83 beast::Journal j);
+
84
+
85// Local function definitions that provides signature compatibility.
+
86TER
+
87offerDelete(
+
88 Application& app,
+
89 ApplyView& view,
+
90 AccountID const& account,
+
91 uint256 const& delIndex,
+
92 std::shared_ptr<SLE> const& sleDel,
+
93 beast::Journal j)
+
94{
+
95 return offerDelete(view, sleDel, j);
+
96}
+
97
+
98TER
+
99removeSignersFromLedger(
+
100 Application& app,
+
101 ApplyView& view,
+
102 AccountID const& account,
+
103 uint256 const& delIndex,
+
104 std::shared_ptr<SLE> const& sleDel,
+
105 beast::Journal j)
+
106{
+
107 return SetSignerList::removeFromLedger(app, view, account, j);
+
108}
+
109
+
110TER
+
111removeTicketFromLedger(
+
112 Application&,
+
113 ApplyView& view,
+
114 AccountID const& account,
+
115 uint256 const& delIndex,
+
116 std::shared_ptr<SLE> const&,
+
117 beast::Journal j)
+
118{
+
119 return Transactor::ticketDelete(view, account, delIndex, j);
+
120}
+
121
+
122TER
+
123removeDepositPreauthFromLedger(
+
124 Application&,
+
125 ApplyView& view,
+
126 AccountID const&,
+
127 uint256 const& delIndex,
+
128 std::shared_ptr<SLE> const&,
+
129 beast::Journal j)
+
130{
+
131 return DepositPreauth::removeFromLedger(view, delIndex, j);
+
132}
+
133
+
134TER
+
135removeNFTokenOfferFromLedger(
+
136 Application& app,
+
137 ApplyView& view,
+
138 AccountID const& account,
+
139 uint256 const& delIndex,
+
140 std::shared_ptr<SLE> const& sleDel,
+
141 beast::Journal)
+
142{
+
143 if (!nft::deleteTokenOffer(view, sleDel))
+
144 return tefBAD_LEDGER;
+
145
+
146 return tesSUCCESS;
+
147}
+
148
+
149TER
+
150removeDIDFromLedger(
+
151 Application& app,
+
152 ApplyView& view,
+
153 AccountID const& account,
+
154 uint256 const& delIndex,
+
155 std::shared_ptr<SLE> const& sleDel,
+
156 beast::Journal j)
+
157{
+
158 return DIDDelete::deleteSLE(view, sleDel, account, j);
+
159}
+
160
+
161TER
+
162removeOracleFromLedger(
+
163 Application&,
+
164 ApplyView& view,
+
165 AccountID const& account,
+
166 uint256 const&,
+
167 std::shared_ptr<SLE> const& sleDel,
+
168 beast::Journal j)
+
169{
+
170 return DeleteOracle::deleteOracle(view, sleDel, account, j);
+
171}
+
172
+
173TER
+
174removeCredentialFromLedger(
+
175 Application&,
+
176 ApplyView& view,
+
177 AccountID const&,
+
178 uint256 const&,
+
179 std::shared_ptr<SLE> const& sleDel,
+
180 beast::Journal j)
+
181{
+
182 return credentials::deleteSLE(view, sleDel, j);
+
183}
+
184
+
185TER
+
186removeDelegateFromLedger(
+
187 Application& app,
+
188 ApplyView& view,
+
189 AccountID const& account,
+
190 uint256 const& delIndex,
+
191 std::shared_ptr<SLE> const& sleDel,
+
192 beast::Journal j)
+
193{
+
194 return DelegateSet::deleteDelegate(view, sleDel, account, j);
+
195}
+
196
+
197// Return nullptr if the LedgerEntryType represents an obligation that can't
+
198// be deleted. Otherwise return the pointer to the function that can delete
+
199// the non-obligation
+
200DeleterFuncPtr
+
201nonObligationDeleter(LedgerEntryType t)
+
202{
+
203 switch (t)
+
204 {
+
205 case ltOFFER:
+
206 return offerDelete;
+
207 case ltSIGNER_LIST:
+
208 return removeSignersFromLedger;
+
209 case ltTICKET:
+
210 return removeTicketFromLedger;
+
211 case ltDEPOSIT_PREAUTH:
+
212 return removeDepositPreauthFromLedger;
+
213 case ltNFTOKEN_OFFER:
+
214 return removeNFTokenOfferFromLedger;
+
215 case ltDID:
+
216 return removeDIDFromLedger;
+
217 case ltORACLE:
+
218 return removeOracleFromLedger;
+
219 case ltCREDENTIAL:
+
220 return removeCredentialFromLedger;
+
221 case ltDELEGATE:
+
222 return removeDelegateFromLedger;
+
223 default:
+
224 return nullptr;
+
225 }
+
226}
+
227
+
228} // namespace
+
229
+
230TER
+
231DeleteAccount::preclaim(PreclaimContext const& ctx)
+
232{
+
233 AccountID const account{ctx.tx[sfAccount]};
+
234 AccountID const dst{ctx.tx[sfDestination]};
+
235
+
236 auto sleDst = ctx.view.read(keylet::account(dst));
+
237
+
238 if (!sleDst)
+
239 return tecNO_DST;
+
240
+
241 if ((*sleDst)[sfFlags] & lsfRequireDestTag && !ctx.tx[~sfDestinationTag])
+
242 return tecDST_TAG_NEEDED;
+
243
+
244 // If credentials are provided - check them anyway
+
245 if (auto const err = credentials::valid(ctx.tx, ctx.view, account, ctx.j);
+
246 !isTesSuccess(err))
+
247 return err;
+
248
+
249 // if credentials then postpone auth check to doApply, to check for expired
+
250 // credentials
+
251 if (!ctx.tx.isFieldPresent(sfCredentialIDs))
+
252 {
+
253 // Check whether the destination account requires deposit authorization.
+
254 if (ctx.view.rules().enabled(featureDepositAuth) &&
+
255 (sleDst->getFlags() & lsfDepositAuth))
+
256 {
+
257 if (!ctx.view.exists(keylet::depositPreauth(dst, account)))
+
258 return tecNO_PERMISSION;
+
259 }
+
260 }
+
261
+
262 auto sleAccount = ctx.view.read(keylet::account(account));
+
263 XRPL_ASSERT(
+
264 sleAccount, "ripple::DeleteAccount::preclaim : non-null account");
+
265 if (!sleAccount)
+
266 return terNO_ACCOUNT;
+
267
+
268 if (ctx.view.rules().enabled(featureNonFungibleTokensV1))
+
269 {
+
270 // If an issuer has any issued NFTs resident in the ledger then it
+
271 // cannot be deleted.
+
272 if ((*sleAccount)[~sfMintedNFTokens] !=
+
273 (*sleAccount)[~sfBurnedNFTokens])
+
274 return tecHAS_OBLIGATIONS;
+
275
+
276 // If the account owns any NFTs it cannot be deleted.
+
277 Keylet const first = keylet::nftpage_min(account);
+
278 Keylet const last = keylet::nftpage_max(account);
+
279
+
280 auto const cp = ctx.view.read(Keylet(
+
281 ltNFTOKEN_PAGE,
+
282 ctx.view.succ(first.key, last.key.next()).value_or(last.key)));
+
283 if (cp)
+
284 return tecHAS_OBLIGATIONS;
+
285 }
+
286
+
287 // We don't allow an account to be deleted if its sequence number
+
288 // is within 256 of the current ledger. This prevents replay of old
+
289 // transactions if this account is resurrected after it is deleted.
+
290 //
+
291 // We look at the account's Sequence rather than the transaction's
+
292 // Sequence in preparation for Tickets.
+
293 constexpr std::uint32_t seqDelta{255};
+
294 if ((*sleAccount)[sfSequence] + seqDelta > ctx.view.seq())
+
295 return tecTOO_SOON;
+
296
+
297 // When fixNFTokenRemint is enabled, we don't allow an account to be
+
298 // deleted if <FirstNFTokenSequence + MintedNFTokens> is within 256 of the
+
299 // current ledger. This is to prevent having duplicate NFTokenIDs after
+
300 // account re-creation.
+
301 //
+
302 // Without this restriction, duplicate NFTokenIDs can be reproduced when
+
303 // authorized minting is involved. Because when the minter mints a NFToken,
+
304 // the issuer's sequence does not change. So when the issuer re-creates
+
305 // their account and mints a NFToken, it is possible that the
+
306 // NFTokenSequence of this NFToken is the same as the one that the
+
307 // authorized minter minted in a previous ledger.
+
308 if (ctx.view.rules().enabled(fixNFTokenRemint) &&
+
309 ((*sleAccount)[~sfFirstNFTokenSequence].value_or(0) +
+
310 (*sleAccount)[~sfMintedNFTokens].value_or(0) + seqDelta >
+
311 ctx.view.seq()))
+
312 return tecTOO_SOON;
+
313
+
314 // Verify that the account does not own any objects that would prevent
+
315 // the account from being deleted.
+
316 Keylet const ownerDirKeylet{keylet::ownerDir(account)};
+
317 if (dirIsEmpty(ctx.view, ownerDirKeylet))
+
318 return tesSUCCESS;
+
319
+
320 std::shared_ptr<SLE const> sleDirNode{};
+
321 unsigned int uDirEntry{0};
+
322 uint256 dirEntry{beast::zero};
+
323
+
324 // Account has no directory at all. This _should_ have been caught
+
325 // by the dirIsEmpty() check earlier, but it's okay to catch it here.
+
326 if (!cdirFirst(
+
327 ctx.view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry))
+
328 return tesSUCCESS;
+
329
+
330 std::int32_t deletableDirEntryCount{0};
+
331 do
+
332 {
+
333 // Make sure any directory node types that we find are the kind
+
334 // we can delete.
+
335 auto sleItem = ctx.view.read(keylet::child(dirEntry));
+
336 if (!sleItem)
+
337 {
+
338 // Directory node has an invalid index. Bail out.
+
339 JLOG(ctx.j.fatal())
+
340 << "DeleteAccount: directory node in ledger " << ctx.view.seq()
+
341 << " has index to object that is missing: "
+
342 << to_string(dirEntry);
+
343 return tefBAD_LEDGER;
+
344 }
+
345
+
346 LedgerEntryType const nodeType{
+
347 safe_cast<LedgerEntryType>((*sleItem)[sfLedgerEntryType])};
+
348
+
349 if (!nonObligationDeleter(nodeType))
+
350 return tecHAS_OBLIGATIONS;
+
351
+
352 // We found a deletable directory entry. Count it. If we find too
+
353 // many deletable directory entries then bail out.
+
354 if (++deletableDirEntryCount > maxDeletableDirEntries)
+
355 return tefTOO_BIG;
+
356
+
357 } while (cdirNext(
+
358 ctx.view, ownerDirKeylet.key, sleDirNode, uDirEntry, dirEntry));
+
359
+
360 return tesSUCCESS;
+
361}
+
362
+
363TER
+
364DeleteAccount::doApply()
+
365{
+
366 auto src = view().peek(keylet::account(account_));
+
367 XRPL_ASSERT(
+
368 src, "ripple::DeleteAccount::doApply : non-null source account");
+
369
+
370 auto const dstID = ctx_.tx[sfDestination];
+
371 auto dst = view().peek(keylet::account(dstID));
+
372 XRPL_ASSERT(
+
373 dst, "ripple::DeleteAccount::doApply : non-null destination account");
+
374
+
375 if (!src || !dst)
+
376 return tefBAD_LEDGER;
+
377
+
378 if (ctx_.view().rules().enabled(featureDepositAuth) &&
+
379 ctx_.tx.isFieldPresent(sfCredentialIDs))
+
380 {
+
381 if (auto err = verifyDepositPreauth(
+
382 ctx_.tx, ctx_.view(), account_, dstID, dst, ctx_.journal);
+
383 !isTesSuccess(err))
+
384 return err;
+
385 }
+
386
+
387 Keylet const ownerDirKeylet{keylet::ownerDir(account_)};
+
388 auto const ter = cleanupOnAccountDelete(
+
389 view(),
+
390 ownerDirKeylet,
+
391 [&](LedgerEntryType nodeType,
+
392 uint256 const& dirEntry,
+
393 std::shared_ptr<SLE>& sleItem) -> std::pair<TER, SkipEntry> {
+
394 if (auto deleter = nonObligationDeleter(nodeType))
+
395 {
+
396 TER const result{
+
397 deleter(ctx_.app, view(), account_, dirEntry, sleItem, j_)};
398
-
399 UNREACHABLE(
-
400 "ripple::DeleteAccount::doApply : undeletable item not found "
-
401 "in preclaim");
-
402 JLOG(j_.error()) << "DeleteAccount undeletable item not "
-
403 "found in preclaim.";
-
404 return {tecHAS_OBLIGATIONS, SkipEntry::No};
-
405 },
-
406 ctx_.journal);
-
407 if (ter != tesSUCCESS)
-
408 return ter;
-
409
-
410 // Transfer any XRP remaining after the fee is paid to the destination:
-
411 (*dst)[sfBalance] = (*dst)[sfBalance] + mSourceBalance;
-
412 (*src)[sfBalance] = (*src)[sfBalance] - mSourceBalance;
-
413 ctx_.deliver(mSourceBalance);
-
414
-
415 XRPL_ASSERT(
-
416 (*src)[sfBalance] == XRPAmount(0),
-
417 "ripple::DeleteAccount::doApply : source balance is zero");
-
418
-
419 // If there's still an owner directory associated with the source account
-
420 // delete it.
-
421 if (view().exists(ownerDirKeylet) && !view().emptyDirDelete(ownerDirKeylet))
-
422 {
-
423 JLOG(j_.error()) << "DeleteAccount cannot delete root dir node of "
-
424 << toBase58(account_);
-
425 return tecHAS_OBLIGATIONS;
-
426 }
-
427
-
428 // Re-arm the password change fee if we can and need to.
-
429 if (mSourceBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
-
430 dst->clearFlag(lsfPasswordSpent);
-
431
-
432 view().update(dst);
-
433 view().erase(src);
+
399 return {result, SkipEntry::No};
+
400 }
+
401
+
402 UNREACHABLE(
+
403 "ripple::DeleteAccount::doApply : undeletable item not found "
+
404 "in preclaim");
+
405 JLOG(j_.error()) << "DeleteAccount undeletable item not "
+
406 "found in preclaim.";
+
407 return {tecHAS_OBLIGATIONS, SkipEntry::No};
+
408 },
+
409 ctx_.journal);
+
410 if (ter != tesSUCCESS)
+
411 return ter;
+
412
+
413 // Transfer any XRP remaining after the fee is paid to the destination:
+
414 (*dst)[sfBalance] = (*dst)[sfBalance] + mSourceBalance;
+
415 (*src)[sfBalance] = (*src)[sfBalance] - mSourceBalance;
+
416 ctx_.deliver(mSourceBalance);
+
417
+
418 XRPL_ASSERT(
+
419 (*src)[sfBalance] == XRPAmount(0),
+
420 "ripple::DeleteAccount::doApply : source balance is zero");
+
421
+
422 // If there's still an owner directory associated with the source account
+
423 // delete it.
+
424 if (view().exists(ownerDirKeylet) && !view().emptyDirDelete(ownerDirKeylet))
+
425 {
+
426 JLOG(j_.error()) << "DeleteAccount cannot delete root dir node of "
+
427 << toBase58(account_);
+
428 return tecHAS_OBLIGATIONS;
+
429 }
+
430
+
431 // Re-arm the password change fee if we can and need to.
+
432 if (mSourceBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
+
433 dst->clearFlag(lsfPasswordSpent);
434
-
435 return tesSUCCESS;
-
436}
+
435 view().update(dst);
+
436 view().erase(src);
437
-
438} // namespace ripple
+
438 return tesSUCCESS;
+
439}
+
440
+
441} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream fatal() const
Definition: Journal.h:352
Stream error() const
Definition: Journal.h:346
@@ -530,9 +533,9 @@ $(function() {
static TER deleteSLE(ApplyContext &ctx, Keylet sleKeylet, AccountID const owner)
Definition: DID.cpp:190
static TER deleteDelegate(ApplyView &view, std::shared_ptr< SLE > const &sle, AccountID const &account, beast::Journal j)
static NotTEC preflight(PreflightContext const &ctx)
-
static TER preclaim(PreclaimContext const &ctx)
-
TER doApply() override
-
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
+
static TER preclaim(PreclaimContext const &ctx)
+
TER doApply() override
+
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
static TER deleteOracle(ApplyView &view, std::shared_ptr< SLE > const &sle, AccountID const &account, beast::Journal j)
static TER removeFromLedger(ApplyView &view, uint256 const &delIndex, beast::Journal j)
A view into a ledger.
Definition: ReadView.h:52
@@ -558,9 +561,9 @@ $(function() {
base_uint next() const
Definition: base_uint.h:455
-
NotTEC checkFields(PreflightContext const &ctx)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER deleteSLE(ApplyView &view, std::shared_ptr< SLE > const &sleCredential, beast::Journal j)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Definition: Indexes.cpp:190
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Definition: Indexes.cpp:403
@@ -581,6 +584,7 @@ $(function() {
@ No
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:1471
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
@ tefBAD_LEDGER
Definition: TER.h:170
@ tefTOO_BIG
Definition: TER.h:184
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:160
@@ -591,7 +595,6 @@ $(function() {
@ tecDST_TAG_NEEDED
Definition: TER.h:309
@ tecHAS_OBLIGATIONS
Definition: TER.h:317
@ tesSUCCESS
Definition: TER.h:244
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:54
@@ -615,6 +618,7 @@ $(function() {
beast::Journal const j
Definition: Transactor.h:87
State information when preflighting a tx.
Definition: Transactor.h:34
Rules const rules
Definition: Transactor.h:38
+
beast::Journal const j
Definition: Transactor.h:41
STTx const & tx
Definition: Transactor.h:37
diff --git a/DeleteAccount_8h_source.html b/DeleteAccount_8h_source.html index 8989df027f..ca7563d9b7 100644 --- a/DeleteAccount_8h_source.html +++ b/DeleteAccount_8h_source.html @@ -134,9 +134,9 @@ $(function() {
DeleteAccount(ApplyContext &ctx)
Definition: DeleteAccount.h:32
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: DeleteAccount.h:30
static NotTEC preflight(PreflightContext const &ctx)
-
static TER preclaim(PreclaimContext const &ctx)
-
TER doApply() override
-
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
+
static TER preclaim(PreclaimContext const &ctx)
+
TER doApply() override
+
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
A view into a ledger.
Definition: ReadView.h:52
Definition: STTx.h:48
Definition: TER.h:411
diff --git a/DepositPreauth_8cpp_source.html b/DepositPreauth_8cpp_source.html index 064c3e730a..57bc631510 100644 --- a/DepositPreauth_8cpp_source.html +++ b/DepositPreauth_8cpp_source.html @@ -431,8 +431,8 @@ $(function() {
T emplace(T... args)
-
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:374
Keylet depositPreauth(AccountID const &owner, AccountID const &preauthorized) noexcept
A DepositPreauth.
Definition: Indexes.cpp:342
diff --git a/Escrow_8cpp_source.html b/Escrow_8cpp_source.html index 68ba92bf8a..2eb0a2f391 100644 --- a/Escrow_8cpp_source.html +++ b/Escrow_8cpp_source.html @@ -750,739 +750,742 @@ $(function() {
672 }
673 }
674
-
675 if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err))
-
676 return err;
-
677
-
678 return tesSUCCESS;
-
679}
-
680
-
681XRPAmount
-
682EscrowFinish::calculateBaseFee(ReadView const& view, STTx const& tx)
-
683{
-
684 XRPAmount extraFee{0};
-
685
-
686 if (auto const fb = tx[~sfFulfillment])
-
687 {
-
688 extraFee += view.fees().base * (32 + (fb->size() / 16));
-
689 }
-
690
-
691 return Transactor::calculateBaseFee(view, tx) + extraFee;
-
692}
-
693
-
694template <ValidIssueType T>
-
695static TER
-
696escrowFinishPreclaimHelper(
-
697 PreclaimContext const& ctx,
-
698 AccountID const& dest,
-
699 STAmount const& amount);
-
700
-
701template <>
-
702TER
-
703escrowFinishPreclaimHelper<Issue>(
-
704 PreclaimContext const& ctx,
-
705 AccountID const& dest,
-
706 STAmount const& amount)
-
707{
-
708 AccountID issuer = amount.getIssuer();
-
709 // If the issuer is the same as the account, return tesSUCCESS
-
710 if (issuer == dest)
-
711 return tesSUCCESS;
-
712
-
713 // If the issuer has requireAuth set, check if the destination is authorized
-
714 if (auto const ter = requireAuth(ctx.view, amount.issue(), dest);
-
715 ter != tesSUCCESS)
-
716 return ter;
-
717
-
718 // If the issuer has deep frozen the destination, return tecFROZEN
-
719 if (isDeepFrozen(ctx.view, dest, amount.getCurrency(), amount.getIssuer()))
-
720 return tecFROZEN;
-
721
-
722 return tesSUCCESS;
-
723}
-
724
-
725template <>
-
726TER
-
727escrowFinishPreclaimHelper<MPTIssue>(
-
728 PreclaimContext const& ctx,
-
729 AccountID const& dest,
-
730 STAmount const& amount)
-
731{
-
732 AccountID issuer = amount.getIssuer();
-
733 // If the issuer is the same as the dest, return tesSUCCESS
-
734 if (issuer == dest)
-
735 return tesSUCCESS;
-
736
-
737 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
-
738 auto const issuanceKey =
-
739 keylet::mptIssuance(amount.get<MPTIssue>().getMptID());
-
740 auto const sleIssuance = ctx.view.read(issuanceKey);
-
741 if (!sleIssuance)
-
742 return tecOBJECT_NOT_FOUND;
-
743
-
744 // If the issuer has requireAuth set, check if the destination is
-
745 // authorized
-
746 auto const& mptIssue = amount.get<MPTIssue>();
-
747 if (auto const ter =
-
748 requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth);
-
749 ter != tesSUCCESS)
-
750 return ter;
-
751
-
752 // If the issuer has frozen the destination, return tecLOCKED
-
753 if (isFrozen(ctx.view, dest, mptIssue))
-
754 return tecLOCKED;
-
755
-
756 return tesSUCCESS;
-
757}
-
758
-
759TER
-
760EscrowFinish::preclaim(PreclaimContext const& ctx)
-
761{
-
762 if (ctx.view.rules().enabled(featureCredentials))
-
763 {
-
764 if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]);
-
765 !isTesSuccess(err))
-
766 return err;
-
767 }
-
768
-
769 if (ctx.view.rules().enabled(featureTokenEscrow))
-
770 {
-
771 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
-
772 auto const slep = ctx.view.read(k);
-
773 if (!slep)
-
774 return tecNO_TARGET;
-
775
-
776 AccountID const dest = (*slep)[sfDestination];
-
777 STAmount const amount = (*slep)[sfAmount];
-
778
-
779 if (!isXRP(amount))
-
780 {
-
781 if (auto const ret = std::visit(
-
782 [&]<typename T>(T const&) {
-
783 return escrowFinishPreclaimHelper<T>(ctx, dest, amount);
-
784 },
-
785 amount.asset().value());
-
786 !isTesSuccess(ret))
-
787 return ret;
-
788 }
-
789 }
-
790 return tesSUCCESS;
-
791}
-
792
-
793template <ValidIssueType T>
-
794static TER
-
795escrowUnlockApplyHelper(
-
796 ApplyView& view,
-
797 Rate lockedRate,
-
798 std::shared_ptr<SLE> const& sleDest,
-
799 STAmount const& xrpBalance,
-
800 STAmount const& amount,
-
801 AccountID const& issuer,
-
802 AccountID const& sender,
-
803 AccountID const& receiver,
-
804 bool createAsset,
-
805 beast::Journal journal);
-
806
-
807template <>
-
808TER
-
809escrowUnlockApplyHelper<Issue>(
-
810 ApplyView& view,
-
811 Rate lockedRate,
-
812 std::shared_ptr<SLE> const& sleDest,
-
813 STAmount const& xrpBalance,
-
814 STAmount const& amount,
-
815 AccountID const& issuer,
-
816 AccountID const& sender,
-
817 AccountID const& receiver,
-
818 bool createAsset,
-
819 beast::Journal journal)
-
820{
-
821 Keylet const trustLineKey = keylet::line(receiver, amount.issue());
-
822 bool const recvLow = issuer > receiver;
-
823 bool const senderIssuer = issuer == sender;
-
824 bool const receiverIssuer = issuer == receiver;
-
825 bool const issuerHigh = issuer > receiver;
-
826
-
827 // LCOV_EXCL_START
-
828 if (senderIssuer)
-
829 return tecINTERNAL;
-
830 // LCOV_EXCL_STOP
-
831
-
832 if (receiverIssuer)
-
833 return tesSUCCESS;
-
834
-
835 if (!view.exists(trustLineKey) && createAsset && !receiverIssuer)
-
836 {
-
837 // Can the account cover the trust line's reserve?
-
838 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
-
839 xrpBalance < view.fees().accountReserve(ownerCount + 1))
-
840 {
-
841 JLOG(journal.trace()) << "Trust line does not exist. "
-
842 "Insufficent reserve to create line.";
-
843
-
844 return tecNO_LINE_INSUF_RESERVE;
-
845 }
-
846
-
847 Currency const currency = amount.getCurrency();
-
848 STAmount initialBalance(amount.issue());
-
849 initialBalance.setIssuer(noAccount());
-
850
-
851 // clang-format off
-
852 if (TER const ter = trustCreate(
-
853 view, // payment sandbox
-
854 recvLow, // is dest low?
-
855 issuer, // source
-
856 receiver, // destination
-
857 trustLineKey.key, // ledger index
-
858 sleDest, // Account to add to
-
859 false, // authorize account
-
860 (sleDest->getFlags() & lsfDefaultRipple) == 0,
-
861 false, // freeze trust line
-
862 false, // deep freeze trust line
-
863 initialBalance, // zero initial balance
-
864 Issue(currency, receiver), // limit of zero
-
865 0, // quality in
-
866 0, // quality out
-
867 journal); // journal
-
868 !isTesSuccess(ter))
-
869 {
-
870 return ter; // LCOV_EXCL_LINE
-
871 }
-
872 // clang-format on
-
873
-
874 view.update(sleDest);
-
875 }
-
876
-
877 if (!view.exists(trustLineKey) && !receiverIssuer)
-
878 return tecNO_LINE;
-
879
-
880 auto const xferRate = transferRate(view, amount);
-
881 // update if issuer rate is less than locked rate
-
882 if (xferRate < lockedRate)
-
883 lockedRate = xferRate;
-
884
-
885 // Transfer Rate only applies when:
-
886 // 1. Issuer is not involved in the transfer (senderIssuer or
-
887 // receiverIssuer)
-
888 // 2. The locked rate is different from the parity rate
-
889
-
890 // NOTE: Transfer fee in escrow works a bit differently from a normal
-
891 // payment. In escrow, the fee is deducted from the locked/sending amount,
-
892 // whereas in a normal payment, the transfer fee is taken on top of the
-
893 // sending amount.
-
894 auto finalAmt = amount;
-
895 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
-
896 {
-
897 // compute transfer fee, if any
-
898 auto const xferFee = amount.value() -
-
899 divideRound(amount, lockedRate, amount.issue(), true);
-
900 // compute balance to transfer
-
901 finalAmt = amount.value() - xferFee;
-
902 }
-
903
-
904 // validate the line limit if the account submitting txn is not the receiver
-
905 // of the funds
-
906 if (!createAsset)
-
907 {
-
908 auto const sleRippleState = view.peek(trustLineKey);
-
909 if (!sleRippleState)
-
910 return tecINTERNAL; // LCOV_EXCL_LINE
-
911
-
912 // if the issuer is the high, then we use the low limit
-
913 // otherwise we use the high limit
-
914 STAmount const lineLimit = sleRippleState->getFieldAmount(
-
915 issuerHigh ? sfLowLimit : sfHighLimit);
-
916
-
917 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
+
675 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
+
676 !isTesSuccess(err))
+
677 return err;
+
678
+
679 return tesSUCCESS;
+
680}
+
681
+
682XRPAmount
+
683EscrowFinish::calculateBaseFee(ReadView const& view, STTx const& tx)
+
684{
+
685 XRPAmount extraFee{0};
+
686
+
687 if (auto const fb = tx[~sfFulfillment])
+
688 {
+
689 extraFee += view.fees().base * (32 + (fb->size() / 16));
+
690 }
+
691
+
692 return Transactor::calculateBaseFee(view, tx) + extraFee;
+
693}
+
694
+
695template <ValidIssueType T>
+
696static TER
+
697escrowFinishPreclaimHelper(
+
698 PreclaimContext const& ctx,
+
699 AccountID const& dest,
+
700 STAmount const& amount);
+
701
+
702template <>
+
703TER
+
704escrowFinishPreclaimHelper<Issue>(
+
705 PreclaimContext const& ctx,
+
706 AccountID const& dest,
+
707 STAmount const& amount)
+
708{
+
709 AccountID issuer = amount.getIssuer();
+
710 // If the issuer is the same as the account, return tesSUCCESS
+
711 if (issuer == dest)
+
712 return tesSUCCESS;
+
713
+
714 // If the issuer has requireAuth set, check if the destination is authorized
+
715 if (auto const ter = requireAuth(ctx.view, amount.issue(), dest);
+
716 ter != tesSUCCESS)
+
717 return ter;
+
718
+
719 // If the issuer has deep frozen the destination, return tecFROZEN
+
720 if (isDeepFrozen(ctx.view, dest, amount.getCurrency(), amount.getIssuer()))
+
721 return tecFROZEN;
+
722
+
723 return tesSUCCESS;
+
724}
+
725
+
726template <>
+
727TER
+
728escrowFinishPreclaimHelper<MPTIssue>(
+
729 PreclaimContext const& ctx,
+
730 AccountID const& dest,
+
731 STAmount const& amount)
+
732{
+
733 AccountID issuer = amount.getIssuer();
+
734 // If the issuer is the same as the dest, return tesSUCCESS
+
735 if (issuer == dest)
+
736 return tesSUCCESS;
+
737
+
738 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
+
739 auto const issuanceKey =
+
740 keylet::mptIssuance(amount.get<MPTIssue>().getMptID());
+
741 auto const sleIssuance = ctx.view.read(issuanceKey);
+
742 if (!sleIssuance)
+
743 return tecOBJECT_NOT_FOUND;
+
744
+
745 // If the issuer has requireAuth set, check if the destination is
+
746 // authorized
+
747 auto const& mptIssue = amount.get<MPTIssue>();
+
748 if (auto const ter =
+
749 requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth);
+
750 ter != tesSUCCESS)
+
751 return ter;
+
752
+
753 // If the issuer has frozen the destination, return tecLOCKED
+
754 if (isFrozen(ctx.view, dest, mptIssue))
+
755 return tecLOCKED;
+
756
+
757 return tesSUCCESS;
+
758}
+
759
+
760TER
+
761EscrowFinish::preclaim(PreclaimContext const& ctx)
+
762{
+
763 if (ctx.view.rules().enabled(featureCredentials))
+
764 {
+
765 if (auto const err =
+
766 credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
+
767 !isTesSuccess(err))
+
768 return err;
+
769 }
+
770
+
771 if (ctx.view.rules().enabled(featureTokenEscrow))
+
772 {
+
773 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
+
774 auto const slep = ctx.view.read(k);
+
775 if (!slep)
+
776 return tecNO_TARGET;
+
777
+
778 AccountID const dest = (*slep)[sfDestination];
+
779 STAmount const amount = (*slep)[sfAmount];
+
780
+
781 if (!isXRP(amount))
+
782 {
+
783 if (auto const ret = std::visit(
+
784 [&]<typename T>(T const&) {
+
785 return escrowFinishPreclaimHelper<T>(ctx, dest, amount);
+
786 },
+
787 amount.asset().value());
+
788 !isTesSuccess(ret))
+
789 return ret;
+
790 }
+
791 }
+
792 return tesSUCCESS;
+
793}
+
794
+
795template <ValidIssueType T>
+
796static TER
+
797escrowUnlockApplyHelper(
+
798 ApplyView& view,
+
799 Rate lockedRate,
+
800 std::shared_ptr<SLE> const& sleDest,
+
801 STAmount const& xrpBalance,
+
802 STAmount const& amount,
+
803 AccountID const& issuer,
+
804 AccountID const& sender,
+
805 AccountID const& receiver,
+
806 bool createAsset,
+
807 beast::Journal journal);
+
808
+
809template <>
+
810TER
+
811escrowUnlockApplyHelper<Issue>(
+
812 ApplyView& view,
+
813 Rate lockedRate,
+
814 std::shared_ptr<SLE> const& sleDest,
+
815 STAmount const& xrpBalance,
+
816 STAmount const& amount,
+
817 AccountID const& issuer,
+
818 AccountID const& sender,
+
819 AccountID const& receiver,
+
820 bool createAsset,
+
821 beast::Journal journal)
+
822{
+
823 Keylet const trustLineKey = keylet::line(receiver, amount.issue());
+
824 bool const recvLow = issuer > receiver;
+
825 bool const senderIssuer = issuer == sender;
+
826 bool const receiverIssuer = issuer == receiver;
+
827 bool const issuerHigh = issuer > receiver;
+
828
+
829 // LCOV_EXCL_START
+
830 if (senderIssuer)
+
831 return tecINTERNAL;
+
832 // LCOV_EXCL_STOP
+
833
+
834 if (receiverIssuer)
+
835 return tesSUCCESS;
+
836
+
837 if (!view.exists(trustLineKey) && createAsset && !receiverIssuer)
+
838 {
+
839 // Can the account cover the trust line's reserve?
+
840 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
+
841 xrpBalance < view.fees().accountReserve(ownerCount + 1))
+
842 {
+
843 JLOG(journal.trace()) << "Trust line does not exist. "
+
844 "Insufficent reserve to create line.";
+
845
+
846 return tecNO_LINE_INSUF_RESERVE;
+
847 }
+
848
+
849 Currency const currency = amount.getCurrency();
+
850 STAmount initialBalance(amount.issue());
+
851 initialBalance.setIssuer(noAccount());
+
852
+
853 // clang-format off
+
854 if (TER const ter = trustCreate(
+
855 view, // payment sandbox
+
856 recvLow, // is dest low?
+
857 issuer, // source
+
858 receiver, // destination
+
859 trustLineKey.key, // ledger index
+
860 sleDest, // Account to add to
+
861 false, // authorize account
+
862 (sleDest->getFlags() & lsfDefaultRipple) == 0,
+
863 false, // freeze trust line
+
864 false, // deep freeze trust line
+
865 initialBalance, // zero initial balance
+
866 Issue(currency, receiver), // limit of zero
+
867 0, // quality in
+
868 0, // quality out
+
869 journal); // journal
+
870 !isTesSuccess(ter))
+
871 {
+
872 return ter; // LCOV_EXCL_LINE
+
873 }
+
874 // clang-format on
+
875
+
876 view.update(sleDest);
+
877 }
+
878
+
879 if (!view.exists(trustLineKey) && !receiverIssuer)
+
880 return tecNO_LINE;
+
881
+
882 auto const xferRate = transferRate(view, amount);
+
883 // update if issuer rate is less than locked rate
+
884 if (xferRate < lockedRate)
+
885 lockedRate = xferRate;
+
886
+
887 // Transfer Rate only applies when:
+
888 // 1. Issuer is not involved in the transfer (senderIssuer or
+
889 // receiverIssuer)
+
890 // 2. The locked rate is different from the parity rate
+
891
+
892 // NOTE: Transfer fee in escrow works a bit differently from a normal
+
893 // payment. In escrow, the fee is deducted from the locked/sending amount,
+
894 // whereas in a normal payment, the transfer fee is taken on top of the
+
895 // sending amount.
+
896 auto finalAmt = amount;
+
897 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
+
898 {
+
899 // compute transfer fee, if any
+
900 auto const xferFee = amount.value() -
+
901 divideRound(amount, lockedRate, amount.issue(), true);
+
902 // compute balance to transfer
+
903 finalAmt = amount.value() - xferFee;
+
904 }
+
905
+
906 // validate the line limit if the account submitting txn is not the receiver
+
907 // of the funds
+
908 if (!createAsset)
+
909 {
+
910 auto const sleRippleState = view.peek(trustLineKey);
+
911 if (!sleRippleState)
+
912 return tecINTERNAL; // LCOV_EXCL_LINE
+
913
+
914 // if the issuer is the high, then we use the low limit
+
915 // otherwise we use the high limit
+
916 STAmount const lineLimit = sleRippleState->getFieldAmount(
+
917 issuerHigh ? sfLowLimit : sfHighLimit);
918
-
919 // flip the sign of the line balance if the issuer is not high
-
920 if (!issuerHigh)
-
921 lineBalance.negate();
-
922
-
923 // add the final amount to the line balance
-
924 lineBalance += finalAmt;
-
925
-
926 // if the transfer would exceed the line limit return tecLIMIT_EXCEEDED
-
927 if (lineLimit < lineBalance)
-
928 return tecLIMIT_EXCEEDED;
-
929 }
-
930
-
931 // if destination is not the issuer then transfer funds
-
932 if (!receiverIssuer)
-
933 {
-
934 auto const ter =
-
935 rippleCredit(view, issuer, receiver, finalAmt, true, journal);
-
936 if (ter != tesSUCCESS)
-
937 return ter; // LCOV_EXCL_LINE
-
938 }
-
939 return tesSUCCESS;
-
940}
-
941
-
942template <>
-
943TER
-
944escrowUnlockApplyHelper<MPTIssue>(
-
945 ApplyView& view,
-
946 Rate lockedRate,
-
947 std::shared_ptr<SLE> const& sleDest,
-
948 STAmount const& xrpBalance,
-
949 STAmount const& amount,
-
950 AccountID const& issuer,
-
951 AccountID const& sender,
-
952 AccountID const& receiver,
-
953 bool createAsset,
-
954 beast::Journal journal)
-
955{
-
956 bool const senderIssuer = issuer == sender;
-
957 bool const receiverIssuer = issuer == receiver;
-
958
-
959 auto const mptID = amount.get<MPTIssue>().getMptID();
-
960 auto const issuanceKey = keylet::mptIssuance(mptID);
-
961 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
-
962 createAsset && !receiverIssuer)
-
963 {
-
964 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
-
965 xrpBalance < view.fees().accountReserve(ownerCount + 1))
-
966 {
-
967 return tecINSUFFICIENT_RESERVE;
-
968 }
-
969
-
970 if (auto const ter =
-
971 MPTokenAuthorize::createMPToken(view, mptID, receiver, 0);
-
972 !isTesSuccess(ter))
-
973 {
-
974 return ter; // LCOV_EXCL_LINE
-
975 }
-
976
-
977 // update owner count.
-
978 adjustOwnerCount(view, sleDest, 1, journal);
-
979 }
-
980
-
981 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
-
982 !receiverIssuer)
-
983 return tecNO_PERMISSION;
-
984
-
985 auto const xferRate = transferRate(view, amount);
-
986 // update if issuer rate is less than locked rate
-
987 if (xferRate < lockedRate)
-
988 lockedRate = xferRate;
-
989
-
990 // Transfer Rate only applies when:
-
991 // 1. Issuer is not involved in the transfer (senderIssuer or
-
992 // receiverIssuer)
-
993 // 2. The locked rate is different from the parity rate
-
994
-
995 // NOTE: Transfer fee in escrow works a bit differently from a normal
-
996 // payment. In escrow, the fee is deducted from the locked/sending amount,
-
997 // whereas in a normal payment, the transfer fee is taken on top of the
-
998 // sending amount.
-
999 auto finalAmt = amount;
-
1000 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
-
1001 {
-
1002 // compute transfer fee, if any
-
1003 auto const xferFee = amount.value() -
-
1004 divideRound(amount, lockedRate, amount.asset(), true);
-
1005 // compute balance to transfer
-
1006 finalAmt = amount.value() - xferFee;
-
1007 }
-
1008
-
1009 return rippleUnlockEscrowMPT(view, sender, receiver, finalAmt, journal);
-
1010}
-
1011
-
1012TER
-
1013EscrowFinish::doApply()
-
1014{
-
1015 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
-
1016 auto const slep = ctx_.view().peek(k);
-
1017 if (!slep)
-
1018 {
-
1019 if (ctx_.view().rules().enabled(featureTokenEscrow))
-
1020 return tecINTERNAL; // LCOV_EXCL_LINE
-
1021
-
1022 return tecNO_TARGET;
-
1023 }
-
1024
-
1025 // If a cancel time is present, a finish operation should only succeed prior
-
1026 // to that time. fix1571 corrects a logic error in the check that would make
-
1027 // a finish only succeed strictly after the cancel time.
-
1028 if (ctx_.view().rules().enabled(fix1571))
-
1029 {
-
1030 auto const now = ctx_.view().info().parentCloseTime;
-
1031
-
1032 // Too soon: can't execute before the finish time
-
1033 if ((*slep)[~sfFinishAfter] && !after(now, (*slep)[sfFinishAfter]))
-
1034 return tecNO_PERMISSION;
-
1035
-
1036 // Too late: can't execute after the cancel time
-
1037 if ((*slep)[~sfCancelAfter] && after(now, (*slep)[sfCancelAfter]))
-
1038 return tecNO_PERMISSION;
-
1039 }
-
1040 else
-
1041 {
-
1042 // Too soon?
-
1043 if ((*slep)[~sfFinishAfter] &&
-
1044 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
-
1045 (*slep)[sfFinishAfter])
-
1046 return tecNO_PERMISSION;
-
1047
-
1048 // Too late?
-
1049 if ((*slep)[~sfCancelAfter] &&
-
1050 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
-
1051 (*slep)[sfCancelAfter])
-
1052 return tecNO_PERMISSION;
-
1053 }
-
1054
-
1055 // Check cryptocondition fulfillment
-
1056 {
-
1057 auto const id = ctx_.tx.getTransactionID();
-
1058 auto flags = ctx_.app.getHashRouter().getFlags(id);
-
1059
-
1060 auto const cb = ctx_.tx[~sfCondition];
+
919 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
+
920
+
921 // flip the sign of the line balance if the issuer is not high
+
922 if (!issuerHigh)
+
923 lineBalance.negate();
+
924
+
925 // add the final amount to the line balance
+
926 lineBalance += finalAmt;
+
927
+
928 // if the transfer would exceed the line limit return tecLIMIT_EXCEEDED
+
929 if (lineLimit < lineBalance)
+
930 return tecLIMIT_EXCEEDED;
+
931 }
+
932
+
933 // if destination is not the issuer then transfer funds
+
934 if (!receiverIssuer)
+
935 {
+
936 auto const ter =
+
937 rippleCredit(view, issuer, receiver, finalAmt, true, journal);
+
938 if (ter != tesSUCCESS)
+
939 return ter; // LCOV_EXCL_LINE
+
940 }
+
941 return tesSUCCESS;
+
942}
+
943
+
944template <>
+
945TER
+
946escrowUnlockApplyHelper<MPTIssue>(
+
947 ApplyView& view,
+
948 Rate lockedRate,
+
949 std::shared_ptr<SLE> const& sleDest,
+
950 STAmount const& xrpBalance,
+
951 STAmount const& amount,
+
952 AccountID const& issuer,
+
953 AccountID const& sender,
+
954 AccountID const& receiver,
+
955 bool createAsset,
+
956 beast::Journal journal)
+
957{
+
958 bool const senderIssuer = issuer == sender;
+
959 bool const receiverIssuer = issuer == receiver;
+
960
+
961 auto const mptID = amount.get<MPTIssue>().getMptID();
+
962 auto const issuanceKey = keylet::mptIssuance(mptID);
+
963 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
+
964 createAsset && !receiverIssuer)
+
965 {
+
966 if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
+
967 xrpBalance < view.fees().accountReserve(ownerCount + 1))
+
968 {
+
969 return tecINSUFFICIENT_RESERVE;
+
970 }
+
971
+
972 if (auto const ter =
+
973 MPTokenAuthorize::createMPToken(view, mptID, receiver, 0);
+
974 !isTesSuccess(ter))
+
975 {
+
976 return ter; // LCOV_EXCL_LINE
+
977 }
+
978
+
979 // update owner count.
+
980 adjustOwnerCount(view, sleDest, 1, journal);
+
981 }
+
982
+
983 if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) &&
+
984 !receiverIssuer)
+
985 return tecNO_PERMISSION;
+
986
+
987 auto const xferRate = transferRate(view, amount);
+
988 // update if issuer rate is less than locked rate
+
989 if (xferRate < lockedRate)
+
990 lockedRate = xferRate;
+
991
+
992 // Transfer Rate only applies when:
+
993 // 1. Issuer is not involved in the transfer (senderIssuer or
+
994 // receiverIssuer)
+
995 // 2. The locked rate is different from the parity rate
+
996
+
997 // NOTE: Transfer fee in escrow works a bit differently from a normal
+
998 // payment. In escrow, the fee is deducted from the locked/sending amount,
+
999 // whereas in a normal payment, the transfer fee is taken on top of the
+
1000 // sending amount.
+
1001 auto finalAmt = amount;
+
1002 if ((!senderIssuer && !receiverIssuer) && lockedRate != parityRate)
+
1003 {
+
1004 // compute transfer fee, if any
+
1005 auto const xferFee = amount.value() -
+
1006 divideRound(amount, lockedRate, amount.asset(), true);
+
1007 // compute balance to transfer
+
1008 finalAmt = amount.value() - xferFee;
+
1009 }
+
1010
+
1011 return rippleUnlockEscrowMPT(view, sender, receiver, finalAmt, journal);
+
1012}
+
1013
+
1014TER
+
1015EscrowFinish::doApply()
+
1016{
+
1017 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
+
1018 auto const slep = ctx_.view().peek(k);
+
1019 if (!slep)
+
1020 {
+
1021 if (ctx_.view().rules().enabled(featureTokenEscrow))
+
1022 return tecINTERNAL; // LCOV_EXCL_LINE
+
1023
+
1024 return tecNO_TARGET;
+
1025 }
+
1026
+
1027 // If a cancel time is present, a finish operation should only succeed prior
+
1028 // to that time. fix1571 corrects a logic error in the check that would make
+
1029 // a finish only succeed strictly after the cancel time.
+
1030 if (ctx_.view().rules().enabled(fix1571))
+
1031 {
+
1032 auto const now = ctx_.view().info().parentCloseTime;
+
1033
+
1034 // Too soon: can't execute before the finish time
+
1035 if ((*slep)[~sfFinishAfter] && !after(now, (*slep)[sfFinishAfter]))
+
1036 return tecNO_PERMISSION;
+
1037
+
1038 // Too late: can't execute after the cancel time
+
1039 if ((*slep)[~sfCancelAfter] && after(now, (*slep)[sfCancelAfter]))
+
1040 return tecNO_PERMISSION;
+
1041 }
+
1042 else
+
1043 {
+
1044 // Too soon?
+
1045 if ((*slep)[~sfFinishAfter] &&
+
1046 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
+
1047 (*slep)[sfFinishAfter])
+
1048 return tecNO_PERMISSION;
+
1049
+
1050 // Too late?
+
1051 if ((*slep)[~sfCancelAfter] &&
+
1052 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
+
1053 (*slep)[sfCancelAfter])
+
1054 return tecNO_PERMISSION;
+
1055 }
+
1056
+
1057 // Check cryptocondition fulfillment
+
1058 {
+
1059 auto const id = ctx_.tx.getTransactionID();
+
1060 auto flags = ctx_.app.getHashRouter().getFlags(id);
1061
-
1062 // It's unlikely that the results of the check will
-
1063 // expire from the hash router, but if it happens,
-
1064 // simply re-run the check.
-
1065 if (cb && !(flags & (SF_CF_INVALID | SF_CF_VALID)))
-
1066 {
-
1067 auto const fb = ctx_.tx[~sfFulfillment];
-
1068
-
1069 if (!fb)
-
1070 return tecINTERNAL;
-
1071
-
1072 if (checkCondition(*fb, *cb))
-
1073 flags = SF_CF_VALID;
-
1074 else
-
1075 flags = SF_CF_INVALID;
-
1076
-
1077 ctx_.app.getHashRouter().setFlags(id, flags);
-
1078 }
-
1079
-
1080 // If the check failed, then simply return an error
-
1081 // and don't look at anything else.
-
1082 if (flags & SF_CF_INVALID)
-
1083 return tecCRYPTOCONDITION_ERROR;
-
1084
-
1085 // Check against condition in the ledger entry:
-
1086 auto const cond = (*slep)[~sfCondition];
-
1087
-
1088 // If a condition wasn't specified during creation,
-
1089 // one shouldn't be included now.
-
1090 if (!cond && cb)
-
1091 return tecCRYPTOCONDITION_ERROR;
-
1092
-
1093 // If a condition was specified during creation of
-
1094 // the suspended payment, the identical condition
-
1095 // must be presented again. We don't check if the
-
1096 // fulfillment matches the condition since we did
-
1097 // that in preflight.
-
1098 if (cond && (cond != cb))
-
1099 return tecCRYPTOCONDITION_ERROR;
-
1100 }
-
1101
-
1102 // NOTE: Escrow payments cannot be used to fund accounts.
-
1103 AccountID const destID = (*slep)[sfDestination];
-
1104 auto const sled = ctx_.view().peek(keylet::account(destID));
-
1105 if (!sled)
-
1106 return tecNO_DST;
-
1107
-
1108 if (ctx_.view().rules().enabled(featureDepositAuth))
-
1109 {
-
1110 if (auto err = verifyDepositPreauth(ctx_, account_, destID, sled);
-
1111 !isTesSuccess(err))
-
1112 return err;
-
1113 }
-
1114
-
1115 AccountID const account = (*slep)[sfAccount];
-
1116
-
1117 // Remove escrow from owner directory
-
1118 {
-
1119 auto const page = (*slep)[sfOwnerNode];
-
1120 if (!ctx_.view().dirRemove(
-
1121 keylet::ownerDir(account), page, k.key, true))
-
1122 {
-
1123 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
-
1124 return tefBAD_LEDGER;
-
1125 }
-
1126 }
-
1127
-
1128 // Remove escrow from recipient's owner directory, if present.
-
1129 if (auto const optPage = (*slep)[~sfDestinationNode])
-
1130 {
-
1131 if (!ctx_.view().dirRemove(
-
1132 keylet::ownerDir(destID), *optPage, k.key, true))
-
1133 {
-
1134 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
-
1135 return tefBAD_LEDGER;
-
1136 }
-
1137 }
-
1138
-
1139 STAmount const amount = slep->getFieldAmount(sfAmount);
-
1140 // Transfer amount to destination
-
1141 if (isXRP(amount))
-
1142 (*sled)[sfBalance] = (*sled)[sfBalance] + amount;
-
1143 else
-
1144 {
-
1145 if (!ctx_.view().rules().enabled(featureTokenEscrow))
-
1146 return temDISABLED; // LCOV_EXCL_LINE
-
1147
-
1148 Rate lockedRate = slep->isFieldPresent(sfTransferRate)
-
1149 ? ripple::Rate(slep->getFieldU32(sfTransferRate))
-
1150 : parityRate;
-
1151 auto const issuer = amount.getIssuer();
-
1152 bool const createAsset = destID == account_;
-
1153 if (auto const ret = std::visit(
-
1154 [&]<typename T>(T const&) {
-
1155 return escrowUnlockApplyHelper<T>(
-
1156 ctx_.view(),
-
1157 lockedRate,
-
1158 sled,
-
1159 mPriorBalance,
-
1160 amount,
-
1161 issuer,
-
1162 account,
-
1163 destID,
-
1164 createAsset,
-
1165 j_);
-
1166 },
-
1167 amount.asset().value());
-
1168 !isTesSuccess(ret))
-
1169 return ret;
-
1170
-
1171 // Remove escrow from issuers owner directory, if present.
-
1172 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
-
1173 {
-
1174 if (!ctx_.view().dirRemove(
-
1175 keylet::ownerDir(issuer), *optPage, k.key, true))
-
1176 {
-
1177 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
-
1178 return tefBAD_LEDGER; // LCOV_EXCL_LINE
-
1179 }
-
1180 }
-
1181 }
-
1182
-
1183 ctx_.view().update(sled);
-
1184
-
1185 // Adjust source owner count
-
1186 auto const sle = ctx_.view().peek(keylet::account(account));
-
1187 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
-
1188 ctx_.view().update(sle);
-
1189
-
1190 // Remove escrow from ledger
-
1191 ctx_.view().erase(slep);
-
1192 return tesSUCCESS;
-
1193}
-
1194
-
1195//------------------------------------------------------------------------------
-
1196
-
1197NotTEC
-
1198EscrowCancel::preflight(PreflightContext const& ctx)
-
1199{
-
1200 if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask)
-
1201 return temINVALID_FLAG;
-
1202
-
1203 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
-
1204 return ret;
+
1062 auto const cb = ctx_.tx[~sfCondition];
+
1063
+
1064 // It's unlikely that the results of the check will
+
1065 // expire from the hash router, but if it happens,
+
1066 // simply re-run the check.
+
1067 if (cb && !(flags & (SF_CF_INVALID | SF_CF_VALID)))
+
1068 {
+
1069 auto const fb = ctx_.tx[~sfFulfillment];
+
1070
+
1071 if (!fb)
+
1072 return tecINTERNAL;
+
1073
+
1074 if (checkCondition(*fb, *cb))
+
1075 flags = SF_CF_VALID;
+
1076 else
+
1077 flags = SF_CF_INVALID;
+
1078
+
1079 ctx_.app.getHashRouter().setFlags(id, flags);
+
1080 }
+
1081
+
1082 // If the check failed, then simply return an error
+
1083 // and don't look at anything else.
+
1084 if (flags & SF_CF_INVALID)
+
1085 return tecCRYPTOCONDITION_ERROR;
+
1086
+
1087 // Check against condition in the ledger entry:
+
1088 auto const cond = (*slep)[~sfCondition];
+
1089
+
1090 // If a condition wasn't specified during creation,
+
1091 // one shouldn't be included now.
+
1092 if (!cond && cb)
+
1093 return tecCRYPTOCONDITION_ERROR;
+
1094
+
1095 // If a condition was specified during creation of
+
1096 // the suspended payment, the identical condition
+
1097 // must be presented again. We don't check if the
+
1098 // fulfillment matches the condition since we did
+
1099 // that in preflight.
+
1100 if (cond && (cond != cb))
+
1101 return tecCRYPTOCONDITION_ERROR;
+
1102 }
+
1103
+
1104 // NOTE: Escrow payments cannot be used to fund accounts.
+
1105 AccountID const destID = (*slep)[sfDestination];
+
1106 auto const sled = ctx_.view().peek(keylet::account(destID));
+
1107 if (!sled)
+
1108 return tecNO_DST;
+
1109
+
1110 if (ctx_.view().rules().enabled(featureDepositAuth))
+
1111 {
+
1112 if (auto err = verifyDepositPreauth(
+
1113 ctx_.tx, ctx_.view(), account_, destID, sled, ctx_.journal);
+
1114 !isTesSuccess(err))
+
1115 return err;
+
1116 }
+
1117
+
1118 AccountID const account = (*slep)[sfAccount];
+
1119
+
1120 // Remove escrow from owner directory
+
1121 {
+
1122 auto const page = (*slep)[sfOwnerNode];
+
1123 if (!ctx_.view().dirRemove(
+
1124 keylet::ownerDir(account), page, k.key, true))
+
1125 {
+
1126 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
+
1127 return tefBAD_LEDGER;
+
1128 }
+
1129 }
+
1130
+
1131 // Remove escrow from recipient's owner directory, if present.
+
1132 if (auto const optPage = (*slep)[~sfDestinationNode])
+
1133 {
+
1134 if (!ctx_.view().dirRemove(
+
1135 keylet::ownerDir(destID), *optPage, k.key, true))
+
1136 {
+
1137 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
+
1138 return tefBAD_LEDGER;
+
1139 }
+
1140 }
+
1141
+
1142 STAmount const amount = slep->getFieldAmount(sfAmount);
+
1143 // Transfer amount to destination
+
1144 if (isXRP(amount))
+
1145 (*sled)[sfBalance] = (*sled)[sfBalance] + amount;
+
1146 else
+
1147 {
+
1148 if (!ctx_.view().rules().enabled(featureTokenEscrow))
+
1149 return temDISABLED; // LCOV_EXCL_LINE
+
1150
+
1151 Rate lockedRate = slep->isFieldPresent(sfTransferRate)
+
1152 ? ripple::Rate(slep->getFieldU32(sfTransferRate))
+
1153 : parityRate;
+
1154 auto const issuer = amount.getIssuer();
+
1155 bool const createAsset = destID == account_;
+
1156 if (auto const ret = std::visit(
+
1157 [&]<typename T>(T const&) {
+
1158 return escrowUnlockApplyHelper<T>(
+
1159 ctx_.view(),
+
1160 lockedRate,
+
1161 sled,
+
1162 mPriorBalance,
+
1163 amount,
+
1164 issuer,
+
1165 account,
+
1166 destID,
+
1167 createAsset,
+
1168 j_);
+
1169 },
+
1170 amount.asset().value());
+
1171 !isTesSuccess(ret))
+
1172 return ret;
+
1173
+
1174 // Remove escrow from issuers owner directory, if present.
+
1175 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
+
1176 {
+
1177 if (!ctx_.view().dirRemove(
+
1178 keylet::ownerDir(issuer), *optPage, k.key, true))
+
1179 {
+
1180 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
+
1181 return tefBAD_LEDGER; // LCOV_EXCL_LINE
+
1182 }
+
1183 }
+
1184 }
+
1185
+
1186 ctx_.view().update(sled);
+
1187
+
1188 // Adjust source owner count
+
1189 auto const sle = ctx_.view().peek(keylet::account(account));
+
1190 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
+
1191 ctx_.view().update(sle);
+
1192
+
1193 // Remove escrow from ledger
+
1194 ctx_.view().erase(slep);
+
1195 return tesSUCCESS;
+
1196}
+
1197
+
1198//------------------------------------------------------------------------------
+
1199
+
1200NotTEC
+
1201EscrowCancel::preflight(PreflightContext const& ctx)
+
1202{
+
1203 if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask)
+
1204 return temINVALID_FLAG;
1205
-
1206 return preflight2(ctx);
-
1207}
+
1206 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
+
1207 return ret;
1208
-
1209template <ValidIssueType T>
-
1210static TER
-
1211escrowCancelPreclaimHelper(
-
1212 PreclaimContext const& ctx,
-
1213 AccountID const& account,
-
1214 STAmount const& amount);
-
1215
-
1216template <>
-
1217TER
-
1218escrowCancelPreclaimHelper<Issue>(
-
1219 PreclaimContext const& ctx,
-
1220 AccountID const& account,
-
1221 STAmount const& amount)
-
1222{
-
1223 AccountID issuer = amount.getIssuer();
-
1224 // If the issuer is the same as the account, return tecINTERNAL
-
1225 if (issuer == account)
-
1226 return tecINTERNAL; // LCOV_EXCL_LINE
-
1227
-
1228 // If the issuer has requireAuth set, check if the account is authorized
-
1229 if (auto const ter = requireAuth(ctx.view, amount.issue(), account);
-
1230 ter != tesSUCCESS)
-
1231 return ter;
-
1232
-
1233 return tesSUCCESS;
-
1234}
+
1209 return preflight2(ctx);
+
1210}
+
1211
+
1212template <ValidIssueType T>
+
1213static TER
+
1214escrowCancelPreclaimHelper(
+
1215 PreclaimContext const& ctx,
+
1216 AccountID const& account,
+
1217 STAmount const& amount);
+
1218
+
1219template <>
+
1220TER
+
1221escrowCancelPreclaimHelper<Issue>(
+
1222 PreclaimContext const& ctx,
+
1223 AccountID const& account,
+
1224 STAmount const& amount)
+
1225{
+
1226 AccountID issuer = amount.getIssuer();
+
1227 // If the issuer is the same as the account, return tecINTERNAL
+
1228 if (issuer == account)
+
1229 return tecINTERNAL; // LCOV_EXCL_LINE
+
1230
+
1231 // If the issuer has requireAuth set, check if the account is authorized
+
1232 if (auto const ter = requireAuth(ctx.view, amount.issue(), account);
+
1233 ter != tesSUCCESS)
+
1234 return ter;
1235
-
1236template <>
-
1237TER
-
1238escrowCancelPreclaimHelper<MPTIssue>(
-
1239 PreclaimContext const& ctx,
-
1240 AccountID const& account,
-
1241 STAmount const& amount)
-
1242{
-
1243 AccountID issuer = amount.getIssuer();
-
1244 // If the issuer is the same as the account, return tecINTERNAL
-
1245 if (issuer == account)
-
1246 return tecINTERNAL; // LCOV_EXCL_LINE
-
1247
-
1248 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
-
1249 auto const issuanceKey =
-
1250 keylet::mptIssuance(amount.get<MPTIssue>().getMptID());
-
1251 auto const sleIssuance = ctx.view.read(issuanceKey);
-
1252 if (!sleIssuance)
-
1253 return tecOBJECT_NOT_FOUND;
-
1254
-
1255 // If the issuer has requireAuth set, check if the account is
-
1256 // authorized
-
1257 auto const& mptIssue = amount.get<MPTIssue>();
-
1258 if (auto const ter =
-
1259 requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth);
-
1260 ter != tesSUCCESS)
-
1261 return ter;
-
1262
-
1263 return tesSUCCESS;
-
1264}
+
1236 return tesSUCCESS;
+
1237}
+
1238
+
1239template <>
+
1240TER
+
1241escrowCancelPreclaimHelper<MPTIssue>(
+
1242 PreclaimContext const& ctx,
+
1243 AccountID const& account,
+
1244 STAmount const& amount)
+
1245{
+
1246 AccountID issuer = amount.getIssuer();
+
1247 // If the issuer is the same as the account, return tecINTERNAL
+
1248 if (issuer == account)
+
1249 return tecINTERNAL; // LCOV_EXCL_LINE
+
1250
+
1251 // If the mpt does not exist, return tecOBJECT_NOT_FOUND
+
1252 auto const issuanceKey =
+
1253 keylet::mptIssuance(amount.get<MPTIssue>().getMptID());
+
1254 auto const sleIssuance = ctx.view.read(issuanceKey);
+
1255 if (!sleIssuance)
+
1256 return tecOBJECT_NOT_FOUND;
+
1257
+
1258 // If the issuer has requireAuth set, check if the account is
+
1259 // authorized
+
1260 auto const& mptIssue = amount.get<MPTIssue>();
+
1261 if (auto const ter =
+
1262 requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth);
+
1263 ter != tesSUCCESS)
+
1264 return ter;
1265
-
1266TER
-
1267EscrowCancel::preclaim(PreclaimContext const& ctx)
-
1268{
-
1269 if (ctx.view.rules().enabled(featureTokenEscrow))
-
1270 {
-
1271 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
-
1272 auto const slep = ctx.view.read(k);
-
1273 if (!slep)
-
1274 return tecNO_TARGET;
-
1275
-
1276 AccountID const account = (*slep)[sfAccount];
-
1277 STAmount const amount = (*slep)[sfAmount];
+
1266 return tesSUCCESS;
+
1267}
+
1268
+
1269TER
+
1270EscrowCancel::preclaim(PreclaimContext const& ctx)
+
1271{
+
1272 if (ctx.view.rules().enabled(featureTokenEscrow))
+
1273 {
+
1274 auto const k = keylet::escrow(ctx.tx[sfOwner], ctx.tx[sfOfferSequence]);
+
1275 auto const slep = ctx.view.read(k);
+
1276 if (!slep)
+
1277 return tecNO_TARGET;
1278
-
1279 if (!isXRP(amount))
-
1280 {
-
1281 if (auto const ret = std::visit(
-
1282 [&]<typename T>(T const&) {
-
1283 return escrowCancelPreclaimHelper<T>(
-
1284 ctx, account, amount);
-
1285 },
-
1286 amount.asset().value());
-
1287 !isTesSuccess(ret))
-
1288 return ret;
-
1289 }
-
1290 }
-
1291 return tesSUCCESS;
-
1292}
-
1293
-
1294TER
-
1295EscrowCancel::doApply()
-
1296{
-
1297 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
-
1298 auto const slep = ctx_.view().peek(k);
-
1299 if (!slep)
-
1300 {
-
1301 if (ctx_.view().rules().enabled(featureTokenEscrow))
-
1302 return tecINTERNAL; // LCOV_EXCL_LINE
-
1303
-
1304 return tecNO_TARGET;
-
1305 }
+
1279 AccountID const account = (*slep)[sfAccount];
+
1280 STAmount const amount = (*slep)[sfAmount];
+
1281
+
1282 if (!isXRP(amount))
+
1283 {
+
1284 if (auto const ret = std::visit(
+
1285 [&]<typename T>(T const&) {
+
1286 return escrowCancelPreclaimHelper<T>(
+
1287 ctx, account, amount);
+
1288 },
+
1289 amount.asset().value());
+
1290 !isTesSuccess(ret))
+
1291 return ret;
+
1292 }
+
1293 }
+
1294 return tesSUCCESS;
+
1295}
+
1296
+
1297TER
+
1298EscrowCancel::doApply()
+
1299{
+
1300 auto const k = keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
+
1301 auto const slep = ctx_.view().peek(k);
+
1302 if (!slep)
+
1303 {
+
1304 if (ctx_.view().rules().enabled(featureTokenEscrow))
+
1305 return tecINTERNAL; // LCOV_EXCL_LINE
1306
-
1307 if (ctx_.view().rules().enabled(fix1571))
-
1308 {
-
1309 auto const now = ctx_.view().info().parentCloseTime;
-
1310
-
1311 // No cancel time specified: can't execute at all.
-
1312 if (!(*slep)[~sfCancelAfter])
-
1313 return tecNO_PERMISSION;
-
1314
-
1315 // Too soon: can't execute before the cancel time.
-
1316 if (!after(now, (*slep)[sfCancelAfter]))
-
1317 return tecNO_PERMISSION;
-
1318 }
-
1319 else
-
1320 {
-
1321 // Too soon?
-
1322 if (!(*slep)[~sfCancelAfter] ||
-
1323 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
-
1324 (*slep)[sfCancelAfter])
-
1325 return tecNO_PERMISSION;
-
1326 }
-
1327
-
1328 AccountID const account = (*slep)[sfAccount];
-
1329
-
1330 // Remove escrow from owner directory
-
1331 {
-
1332 auto const page = (*slep)[sfOwnerNode];
-
1333 if (!ctx_.view().dirRemove(
-
1334 keylet::ownerDir(account), page, k.key, true))
-
1335 {
-
1336 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
-
1337 return tefBAD_LEDGER;
-
1338 }
-
1339 }
-
1340
-
1341 // Remove escrow from recipient's owner directory, if present.
-
1342 if (auto const optPage = (*slep)[~sfDestinationNode]; optPage)
-
1343 {
-
1344 if (!ctx_.view().dirRemove(
-
1345 keylet::ownerDir((*slep)[sfDestination]),
-
1346 *optPage,
-
1347 k.key,
-
1348 true))
-
1349 {
-
1350 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
-
1351 return tefBAD_LEDGER;
-
1352 }
-
1353 }
-
1354
-
1355 auto const sle = ctx_.view().peek(keylet::account(account));
-
1356 STAmount const amount = slep->getFieldAmount(sfAmount);
+
1307 return tecNO_TARGET;
+
1308 }
+
1309
+
1310 if (ctx_.view().rules().enabled(fix1571))
+
1311 {
+
1312 auto const now = ctx_.view().info().parentCloseTime;
+
1313
+
1314 // No cancel time specified: can't execute at all.
+
1315 if (!(*slep)[~sfCancelAfter])
+
1316 return tecNO_PERMISSION;
+
1317
+
1318 // Too soon: can't execute before the cancel time.
+
1319 if (!after(now, (*slep)[sfCancelAfter]))
+
1320 return tecNO_PERMISSION;
+
1321 }
+
1322 else
+
1323 {
+
1324 // Too soon?
+
1325 if (!(*slep)[~sfCancelAfter] ||
+
1326 ctx_.view().info().parentCloseTime.time_since_epoch().count() <=
+
1327 (*slep)[sfCancelAfter])
+
1328 return tecNO_PERMISSION;
+
1329 }
+
1330
+
1331 AccountID const account = (*slep)[sfAccount];
+
1332
+
1333 // Remove escrow from owner directory
+
1334 {
+
1335 auto const page = (*slep)[sfOwnerNode];
+
1336 if (!ctx_.view().dirRemove(
+
1337 keylet::ownerDir(account), page, k.key, true))
+
1338 {
+
1339 JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
+
1340 return tefBAD_LEDGER;
+
1341 }
+
1342 }
+
1343
+
1344 // Remove escrow from recipient's owner directory, if present.
+
1345 if (auto const optPage = (*slep)[~sfDestinationNode]; optPage)
+
1346 {
+
1347 if (!ctx_.view().dirRemove(
+
1348 keylet::ownerDir((*slep)[sfDestination]),
+
1349 *optPage,
+
1350 k.key,
+
1351 true))
+
1352 {
+
1353 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
+
1354 return tefBAD_LEDGER;
+
1355 }
+
1356 }
1357
-
1358 // Transfer amount back to the owner
-
1359 if (isXRP(amount))
-
1360 (*sle)[sfBalance] = (*sle)[sfBalance] + amount;
-
1361 else
-
1362 {
-
1363 if (!ctx_.view().rules().enabled(featureTokenEscrow))
-
1364 return temDISABLED; // LCOV_EXCL_LINE
-
1365
-
1366 auto const issuer = amount.getIssuer();
-
1367 bool const createAsset = account == account_;
-
1368 if (auto const ret = std::visit(
-
1369 [&]<typename T>(T const&) {
-
1370 return escrowUnlockApplyHelper<T>(
-
1371 ctx_.view(),
-
1372 parityRate,
-
1373 slep,
-
1374 mPriorBalance,
-
1375 amount,
-
1376 issuer,
-
1377 account, // sender and receiver are the same
-
1378 account,
-
1379 createAsset,
-
1380 j_);
-
1381 },
-
1382 amount.asset().value());
-
1383 !isTesSuccess(ret))
-
1384 return ret; // LCOV_EXCL_LINE
-
1385
-
1386 // Remove escrow from issuers owner directory, if present.
-
1387 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
-
1388 {
-
1389 if (!ctx_.view().dirRemove(
-
1390 keylet::ownerDir(issuer), *optPage, k.key, true))
-
1391 {
-
1392 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
-
1393 return tefBAD_LEDGER; // LCOV_EXCL_LINE
-
1394 }
-
1395 }
-
1396 }
-
1397
-
1398 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
-
1399 ctx_.view().update(sle);
+
1358 auto const sle = ctx_.view().peek(keylet::account(account));
+
1359 STAmount const amount = slep->getFieldAmount(sfAmount);
+
1360
+
1361 // Transfer amount back to the owner
+
1362 if (isXRP(amount))
+
1363 (*sle)[sfBalance] = (*sle)[sfBalance] + amount;
+
1364 else
+
1365 {
+
1366 if (!ctx_.view().rules().enabled(featureTokenEscrow))
+
1367 return temDISABLED; // LCOV_EXCL_LINE
+
1368
+
1369 auto const issuer = amount.getIssuer();
+
1370 bool const createAsset = account == account_;
+
1371 if (auto const ret = std::visit(
+
1372 [&]<typename T>(T const&) {
+
1373 return escrowUnlockApplyHelper<T>(
+
1374 ctx_.view(),
+
1375 parityRate,
+
1376 slep,
+
1377 mPriorBalance,
+
1378 amount,
+
1379 issuer,
+
1380 account, // sender and receiver are the same
+
1381 account,
+
1382 createAsset,
+
1383 j_);
+
1384 },
+
1385 amount.asset().value());
+
1386 !isTesSuccess(ret))
+
1387 return ret; // LCOV_EXCL_LINE
+
1388
+
1389 // Remove escrow from issuers owner directory, if present.
+
1390 if (auto const optPage = (*slep)[~sfIssuerNode]; optPage)
+
1391 {
+
1392 if (!ctx_.view().dirRemove(
+
1393 keylet::ownerDir(issuer), *optPage, k.key, true))
+
1394 {
+
1395 JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
+
1396 return tefBAD_LEDGER; // LCOV_EXCL_LINE
+
1397 }
+
1398 }
+
1399 }
1400
-
1401 // Remove escrow from ledger
-
1402 ctx_.view().erase(slep);
+
1401 adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
+
1402 ctx_.view().update(sle);
1403
-
1404 return tesSUCCESS;
-
1405}
+
1404 // Remove escrow from ledger
+
1405 ctx_.view().erase(slep);
1406
-
1407} // namespace ripple
+
1407 return tesSUCCESS;
+
1408}
+
1409
+
1410} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream fatal() const
Definition: Journal.h:352
Stream debug() const
Definition: Journal.h:328
@@ -1500,17 +1503,17 @@ $(function() {
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
constexpr value_type const & value() const
Definition: Asset.h:156
-
TER doApply() override
Definition: Escrow.cpp:1295
-
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:1198
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:1267
+
TER doApply() override
Definition: Escrow.cpp:1298
+
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:1201
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:1270
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:122
TER doApply() override
Definition: Escrow.cpp:455
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: Escrow.cpp:82
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:363
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:760
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:761
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:628
-
TER doApply() override
Definition: Escrow.cpp:1013
-
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: Escrow.cpp:682
+
TER doApply() override
Definition: Escrow.cpp:1015
+
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: Escrow.cpp:683
int getFlags(uint256 const &key)
Definition: HashRouter.cpp:95
bool setFlags(uint256 const &key, int flags)
Set the flags on a hash.
Definition: HashRouter.cpp:103
A currency issued by an account.
Definition: Issue.h:36
@@ -1556,8 +1559,8 @@ $(function() {
T message(T... args)
-
NotTEC checkFields(PreflightContext const &ctx)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition: Indexes.cpp:540
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:244
@@ -1568,7 +1571,7 @@ $(function() {
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
TER rippleLockEscrowMPT(ApplyView &view, AccountID const &sender, STAmount const &amount, beast::Journal j)
Definition: View.cpp:2740
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:185
-
TER escrowFinishPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition: Escrow.cpp:703
+
TER escrowFinishPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition: Escrow.cpp:704
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:133
@ fhIGNORE_FREEZE
Definition: View.h:78
TER escrowCreatePreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
Definition: Escrow.cpp:283
@@ -1584,12 +1587,13 @@ $(function() {
@ lsfDefaultRipple
@ lsfAllowTrustLineLocking
@ lsfDisallowXRP
-
TER escrowCancelPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition: Escrow.cpp:1238
+
TER escrowCancelPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition: Escrow.cpp:1241
static TER escrowLockApplyHelper(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
@ ahIGNORE_AUTH
Definition: View.h:81
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:1049
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
Definition: Rate2.cpp:104
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:249
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
Definition: View.cpp:2509
@ tefBAD_LEDGER
Definition: TER.h:170
@@ -1599,7 +1603,7 @@ $(function() {
static bool adjustOwnerCount(ApplyContext &ctx, int count)
Definition: SetOracle.cpp:186
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:160
static bool checkCondition(Slice f, Slice c)
Definition: Escrow.cpp:610
-
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition: Escrow.cpp:944
+
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition: Escrow.cpp:946
static NotTEC escrowCreatePreflightHelper(PreflightContext const &ctx)
static TER escrowCancelPreclaimHelper(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
Definition: View.cpp:1227
@@ -1622,22 +1626,21 @@ $(function() {
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:307
@ tecLOCKED
Definition: TER.h:358
@ tesSUCCESS
Definition: TER.h:244
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:386
NotTEC escrowCreatePreflightHelper< MPTIssue >(PreflightContext const &ctx)
Definition: Escrow.cpp:108
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
-
TER escrowFinishPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition: Escrow.cpp:727
+
TER escrowFinishPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Definition: Escrow.cpp:728
NotTEC escrowCreatePreflightHelper< Issue >(PreflightContext const &ctx)
Definition: Escrow.cpp:94
@ WeakAuth
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: View.cpp:2984
constexpr std::uint32_t tfUniversalMask
Definition: TxFlags.h:63
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition: View.cpp:2656
-
TER escrowCancelPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition: Escrow.cpp:1218
+
TER escrowCancelPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
Definition: Escrow.cpp:1221
TER escrowLockApplyHelper< MPTIssue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
Definition: Escrow.cpp:435
static TER escrowUnlockApplyHelper(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition: View.cpp:1140
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:605
-
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition: Escrow.cpp:809
+
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Definition: Escrow.cpp:811
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
static TER escrowCreatePreclaimHelper(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
@ temBAD_AMOUNT
Definition: TER.h:89
diff --git a/Escrow_8h_source.html b/Escrow_8h_source.html index 75d189fd22..d2dcf707b4 100644 --- a/Escrow_8h_source.html +++ b/Escrow_8h_source.html @@ -176,9 +176,9 @@ $(function() {
Definition: Escrow.h:76
EscrowCancel(ApplyContext &ctx)
Definition: Escrow.h:80
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: Escrow.h:78
-
TER doApply() override
Definition: Escrow.cpp:1295
-
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:1198
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:1267
+
TER doApply() override
Definition: Escrow.cpp:1298
+
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:1201
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:1270
Definition: Escrow.h:28
EscrowCreate(ApplyContext &ctx)
Definition: Escrow.h:32
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:122
@@ -187,11 +187,11 @@ $(function() {
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: Escrow.h:30
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:363
Definition: Escrow.h:52
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:760
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Escrow.cpp:761
static NotTEC preflight(PreflightContext const &ctx)
Definition: Escrow.cpp:628
-
TER doApply() override
Definition: Escrow.cpp:1013
+
TER doApply() override
Definition: Escrow.cpp:1015
EscrowFinish(ApplyContext &ctx)
Definition: Escrow.h:56
-
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: Escrow.cpp:682
+
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: Escrow.cpp:683
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: Escrow.h:54
A view into a ledger.
Definition: ReadView.h:52
Definition: STTx.h:48
diff --git a/GatewayBalances_8cpp_source.html b/GatewayBalances_8cpp_source.html index 2666234856..8418f84d0b 100644 --- a/GatewayBalances_8cpp_source.html +++ b/GatewayBalances_8cpp_source.html @@ -181,24 +181,24 @@ $(function() {
103 };
104
105 Json::Value const& hw = params[jss::hotwallet];
-
106 bool valid = true;
+
106 bool valid = true;
107
108 // null is treated as a valid 0-sized array of hotwallet
109 if (hw.isArrayOrNull())
110 {
111 for (unsigned i = 0; i < hw.size(); ++i)
-
112 valid &= addHotWallet(hw[i]);
+
112 valid &= addHotWallet(hw[i]);
113 }
114 else if (hw.isString())
115 {
-
116 valid &= addHotWallet(hw);
+
116 valid &= addHotWallet(hw);
117 }
118 else
119 {
-
120 valid = false;
+
120 valid = false;
121 }
122
-
123 if (!valid)
+
123 if (!valid)
124 {
125 // The documentation states that invalidParams is used when
126 // One or more fields are specified incorrectly.
@@ -388,7 +388,7 @@ $(function() {
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:622
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:276
Charge const feeHeavyBurdenRPC
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Json::Value entry(jtx::Env &env, jtx::Account const &account, jtx::Account const &authorize)
Definition: delegate.cpp:55
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
diff --git a/InvariantCheck_8cpp_source.html b/InvariantCheck_8cpp_source.html index 11836e93f2..576c9c44f3 100644 --- a/InvariantCheck_8cpp_source.html +++ b/InvariantCheck_8cpp_source.html @@ -2238,7 +2238,7 @@ $(function() {
base_uint next() const
Definition: base_uint.h:455
T invoke(T... args)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition: Indexes.cpp:570
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:446
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
diff --git a/LedgerEntry_8cpp_source.html b/LedgerEntry_8cpp_source.html index 3625b29f99..018378c239 100644 --- a/LedgerEntry_8cpp_source.html +++ b/LedgerEntry_8cpp_source.html @@ -893,9 +893,9 @@ $(function() {
815 auto const issuingChainDoor = parseBase58<AccountID>(
816 claim_id[sfIssuingChainDoor.getJsonName()].asString());
817 Issue lockingChainIssue, issuingChainIssue;
-
818 bool valid = lockingChainDoor && issuingChainDoor;
+
818 bool valid = lockingChainDoor && issuingChainDoor;
819
-
820 if (valid)
+
820 if (valid)
821 {
822 try
823 {
@@ -911,7 +911,7 @@ $(function() {
833 }
834 }
835
-
836 if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
+
836 if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral())
837 {
838 auto const seq = claim_id[jss::xchain_owned_claim_id].asUInt();
839
@@ -969,8 +969,8 @@ $(function() {
891 auto const issuingChainDoor = parseBase58<AccountID>(
892 claim_id[sfIssuingChainDoor.getJsonName()].asString());
893 Issue lockingChainIssue, issuingChainIssue;
-
894 bool valid = lockingChainDoor && issuingChainDoor;
-
895 if (valid)
+
894 bool valid = lockingChainDoor && issuingChainDoor;
+
895 if (valid)
896 {
897 try
898 {
@@ -981,12 +981,12 @@ $(function() {
903 }
904 catch (std::runtime_error const& ex)
905 {
-
906 valid = false;
+
906 valid = false;
907 jvResult[jss::error] = "malformedRequest";
908 }
909 }
910
-
911 if (valid &&
+
911 if (valid &&
912 claim_id[jss::xchain_owned_create_account_claim_id].isIntegral())
913 {
914 auto const seq =
@@ -1253,8 +1253,8 @@ $(function() {
bool lexicalCastChecked(Out &out, In in)
Intelligently convert from one type to another.
Definition: LexicalCast.h:202
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:408
Status lookupLedger(std::shared_ptr< ReadView const > &ledger, JsonContext &context, Json::Value &result)
Look up a ledger from a request and fill a Json::Result with the data representing a ledger.
Definition: RPCHelpers.cpp:622
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition: Indexes.cpp:540
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Definition: Indexes.cpp:520
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition: Indexes.cpp:465
diff --git a/LedgerHistory_8cpp_source.html b/LedgerHistory_8cpp_source.html index b248792808..cb34ad3444 100644 --- a/LedgerHistory_8cpp_source.html +++ b/LedgerHistory_8cpp_source.html @@ -416,24 +416,24 @@ $(function() {
338void
339LedgerHistory::handleMismatch(
340 LedgerHash const& built,
-
341 LedgerHash const& valid,
+
341 LedgerHash const& valid,
342 std::optional<uint256> const& builtConsensusHash,
343 std::optional<uint256> const& validatedConsensusHash,
344 Json::Value const& consensus)
345{
346 XRPL_ASSERT(
-
347 built != valid,
+
347 built != valid,
348 "ripple::LedgerHistory::handleMismatch : unequal hashes");
349 ++mismatch_counter_;
350
351 auto builtLedger = getLedgerByHash(built);
-
352 auto validLedger = getLedgerByHash(valid);
+
352 auto validLedger = getLedgerByHash(valid);
353
354 if (!builtLedger || !validLedger)
355 {
356 JLOG(j_.error()) << "MISMATCH cannot be analyzed:"
357 << " builtLedger: " << to_string(built) << " -> "
-
358 << builtLedger << " validLedger: " << to_string(valid)
+
358 << builtLedger << " validLedger: " << to_string(valid)
359 << " -> " << validLedger;
360 return;
361 }
@@ -673,7 +673,7 @@ $(function() {
T emplace(T... args)
T end(T... args)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
SizedItem
Definition: Config.h:44
@ ledgerSize
diff --git a/LedgerHistory_8h_source.html b/LedgerHistory_8h_source.html index 02cbf7b8da..b149ae7b32 100644 --- a/LedgerHistory_8h_source.html +++ b/LedgerHistory_8h_source.html @@ -163,7 +163,7 @@ $(function() {
117 void
118 handleMismatch(
119 LedgerHash const& built,
-
120 LedgerHash const& valid,
+
120 LedgerHash const& valid,
121 std::optional<uint256> const& builtConsensusHash,
122 std::optional<uint256> const& validatedConsensusHash,
123 Json::Value const& consensus);
@@ -232,7 +232,7 @@ $(function() {
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
diff --git a/LedgerMaster_8cpp_source.html b/LedgerMaster_8cpp_source.html index 8b9168e1fa..6b9e5c2384 100644 --- a/LedgerMaster_8cpp_source.html +++ b/LedgerMaster_8cpp_source.html @@ -1771,14 +1771,14 @@ $(function() {
1708 if (index <= mValidLedgerSeq)
1709 {
1710 // Always prefer a validated ledger
-
1711 if (auto valid = mValidLedger.get())
+
1711 if (auto valid = mValidLedger.get())
1712 {
-
1713 if (valid->info().seq == index)
-
1714 return valid;
+
1713 if (valid->info().seq == index)
+
1714 return valid;
1715
1716 try
1717 {
-
1718 auto const hash = hashOfSeq(*valid, index, m_journal);
+
1718 auto const hash = hashOfSeq(*valid, index, m_journal);
1719
1720 if (hash)
1721 return mLedgerHistory.getLedgerByHash(*hash);
@@ -2555,7 +2555,7 @@ $(function() {
bool isRippledVersion(std::uint64_t version)
Check if the encoded software version is a rippled software version.
Definition: BuildInfo.cpp:165
Charge const feeMalformedRequest
Schedule of fees charged for imposing load on the server.
Charge const feeRequestNoReply
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
SizedItem
Definition: Config.h:44
@ ledgerFetch
diff --git a/NetworkOPs_8cpp_source.html b/NetworkOPs_8cpp_source.html index b96958218a..dc6288bcd7 100644 --- a/NetworkOPs_8cpp_source.html +++ b/NetworkOPs_8cpp_source.html @@ -2915,11 +2915,11 @@ $(function() {
2901 escalationMetrics.referenceFeeLevel);
2902 }
2903
-
2904 bool valid = false;
+
2904 bool valid = false;
2905 auto lpClosed = m_ledgerMaster.getValidatedLedger();
2906
2907 if (lpClosed)
-
2908 valid = true;
+
2908 valid = true;
2909 else
2910 lpClosed = m_ledgerMaster.getClosedLedger();
2911
@@ -2972,7 +2972,7 @@ $(function() {
2958 }
2959 }
2960
-
2961 if (valid)
+
2961 if (valid)
2962 info[jss::validated_ledger] = l;
2963 else
2964 info[jss::closed_ledger] = l;
@@ -5255,7 +5255,7 @@ $(function() {
void insertMPTokenIssuanceID(Json::Value &response, std::shared_ptr< STTx const > const &transaction, TxMeta const &transactionMeta)
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.
Charge const feeMediumBurdenRPC
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Definition: Indexes.cpp:380
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:274
diff --git a/PathRequest_8cpp_source.html b/PathRequest_8cpp_source.html index 9cf9ce0774..197726c5ad 100644 --- a/PathRequest_8cpp_source.html +++ b/PathRequest_8cpp_source.html @@ -324,18 +324,18 @@ $(function() {
246 std::shared_ptr<RippleLineCache> const& cache,
247 Json::Value const& value)
248{
-
249 bool valid = false;
+
249 bool valid = false;
250
251 if (parseJson(value) != PFR_PJ_INVALID)
252 {
-
253 valid = isValid(cache);
-
254 if (!hasCompletion() && valid)
+
253 valid = isValid(cache);
+
254 if (!hasCompletion() && valid)
255 doUpdate(cache, true);
256 }
257
258 if (auto stream = m_journal.debug())
259 {
-
260 if (valid)
+
260 if (valid)
261 {
262 stream << iIdentifier << " valid: " << toBase58(*raSrcAccount);
263 stream << iIdentifier << " deliver: " << saDstAmount.getFullText();
@@ -346,7 +346,7 @@ $(function() {
268 }
269 }
270
-
271 return {valid, jvStatus};
+
271 return {valid, jvStatus};
272}
273
274int
@@ -955,7 +955,7 @@ $(function() {
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
static int constexpr max_src_cur
Maximum number of source currencies allowed in a path find request.
static int constexpr max_auto_src_cur
Maximum number of auto source currencies in a path find request.
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string transHuman(TER code)
Definition: TER.cpp:273
diff --git a/PathRequests_8cpp_source.html b/PathRequests_8cpp_source.html index eccdc45e96..035e96bda6 100644 --- a/PathRequests_8cpp_source.html +++ b/PathRequests_8cpp_source.html @@ -330,10 +330,10 @@ $(function() {
255 auto req = std::make_shared<PathRequest>(
256 app_, subscriber, ++mLastIdentifier, *this, mJournal);
257
-
258 auto [valid, jvRes] =
+
258 auto [valid, jvRes] =
259 req->doCreate(getLineCache(inLedger, false), requestJson);
260
-
261 if (valid)
+
261 if (valid)
262 {
263 subscriber->setRequest(req);
264 insertPathRequest(req);
@@ -356,9 +356,9 @@ $(function() {
281 req = std::make_shared<PathRequest>(
282 app_, completion, consumer, ++mLastIdentifier, *this, mJournal);
283
-
284 auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request);
+
284 auto [valid, jvRes] = req->doCreate(getLineCache(inLedger, false), request);
285
-
286 if (!valid)
+
286 if (!valid)
287 {
288 req.reset();
289 }
@@ -388,8 +388,8 @@ $(function() {
313 auto req = std::make_shared<PathRequest>(
314 app_, [] {}, consumer, ++mLastIdentifier, *this, mJournal);
315
-
316 auto [valid, jvRes] = req->doCreate(cache, request);
-
317 if (valid)
+
316 auto [valid, jvRes] = req->doCreate(cache, request);
+
317 if (valid)
318 jvRes = req->doUpdate(cache, false);
319 return std::move(jvRes);
320}
@@ -424,7 +424,7 @@ $(function() {
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
diff --git a/PayChan_8cpp_source.html b/PayChan_8cpp_source.html index ad6b980f48..891ca128a4 100644 --- a/PayChan_8cpp_source.html +++ b/PayChan_8cpp_source.html @@ -551,132 +551,135 @@ $(function() {
473 return temBAD_SIGNATURE;
474 }
475
-
476 if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err))
-
477 return err;
-
478
-
479 return preflight2(ctx);
-
480}
-
481
-
482TER
-
483PayChanClaim::preclaim(PreclaimContext const& ctx)
-
484{
-
485 if (!ctx.view.rules().enabled(featureCredentials))
-
486 return Transactor::preclaim(ctx);
-
487
-
488 if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]);
-
489 !isTesSuccess(err))
-
490 return err;
-
491
-
492 return tesSUCCESS;
-
493}
-
494
-
495TER
-
496PayChanClaim::doApply()
-
497{
-
498 Keylet const k(ltPAYCHAN, ctx_.tx[sfChannel]);
-
499 auto const slep = ctx_.view().peek(k);
-
500 if (!slep)
-
501 return tecNO_TARGET;
-
502
-
503 AccountID const src = (*slep)[sfAccount];
-
504 AccountID const dst = (*slep)[sfDestination];
-
505 AccountID const txAccount = ctx_.tx[sfAccount];
-
506
-
507 auto const curExpiration = (*slep)[~sfExpiration];
-
508 {
-
509 auto const cancelAfter = (*slep)[~sfCancelAfter];
-
510 auto const closeTime =
-
511 ctx_.view().info().parentCloseTime.time_since_epoch().count();
-
512 if ((cancelAfter && closeTime >= *cancelAfter) ||
-
513 (curExpiration && closeTime >= *curExpiration))
-
514 return closeChannel(
-
515 slep, ctx_.view(), k.key, ctx_.app.journal("View"));
-
516 }
-
517
-
518 if (txAccount != src && txAccount != dst)
-
519 return tecNO_PERMISSION;
-
520
-
521 if (ctx_.tx[~sfBalance])
-
522 {
-
523 auto const chanBalance = slep->getFieldAmount(sfBalance).xrp();
-
524 auto const chanFunds = slep->getFieldAmount(sfAmount).xrp();
-
525 auto const reqBalance = ctx_.tx[sfBalance].xrp();
-
526
-
527 if (txAccount == dst && !ctx_.tx[~sfSignature])
-
528 return temBAD_SIGNATURE;
-
529
-
530 if (ctx_.tx[~sfSignature])
-
531 {
-
532 PublicKey const pk((*slep)[sfPublicKey]);
-
533 if (ctx_.tx[sfPublicKey] != pk)
-
534 return temBAD_SIGNER;
-
535 }
-
536
-
537 if (reqBalance > chanFunds)
-
538 return tecUNFUNDED_PAYMENT;
-
539
-
540 if (reqBalance <= chanBalance)
-
541 // nothing requested
-
542 return tecUNFUNDED_PAYMENT;
-
543
-
544 auto const sled = ctx_.view().peek(keylet::account(dst));
-
545 if (!sled)
-
546 return tecNO_DST;
-
547
-
548 // Obeying the lsfDisallowXRP flag was a bug. Piggyback on
-
549 // featureDepositAuth to remove the bug.
-
550 bool const depositAuth{ctx_.view().rules().enabled(featureDepositAuth)};
-
551 if (!depositAuth &&
-
552 (txAccount == src && (sled->getFlags() & lsfDisallowXRP)))
-
553 return tecNO_TARGET;
-
554
-
555 if (depositAuth)
-
556 {
-
557 if (auto err = verifyDepositPreauth(ctx_, txAccount, dst, sled);
-
558 !isTesSuccess(err))
-
559 return err;
-
560 }
-
561
-
562 (*slep)[sfBalance] = ctx_.tx[sfBalance];
-
563 XRPAmount const reqDelta = reqBalance - chanBalance;
-
564 XRPL_ASSERT(
-
565 reqDelta >= beast::zero,
-
566 "ripple::PayChanClaim::doApply : minimum balance delta");
-
567 (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
-
568 ctx_.view().update(sled);
-
569 ctx_.view().update(slep);
-
570 }
-
571
-
572 if (ctx_.tx.getFlags() & tfRenew)
-
573 {
-
574 if (src != txAccount)
-
575 return tecNO_PERMISSION;
-
576 (*slep)[~sfExpiration] = std::nullopt;
-
577 ctx_.view().update(slep);
-
578 }
-
579
-
580 if (ctx_.tx.getFlags() & tfClose)
-
581 {
-
582 // Channel will close immediately if dry or the receiver closes
-
583 if (dst == txAccount || (*slep)[sfBalance] == (*slep)[sfAmount])
-
584 return closeChannel(
-
585 slep, ctx_.view(), k.key, ctx_.app.journal("View"));
-
586
-
587 auto const settleExpiration =
-
588 ctx_.view().info().parentCloseTime.time_since_epoch().count() +
-
589 (*slep)[sfSettleDelay];
-
590
-
591 if (!curExpiration || *curExpiration > settleExpiration)
-
592 {
-
593 (*slep)[~sfExpiration] = settleExpiration;
-
594 ctx_.view().update(slep);
-
595 }
-
596 }
-
597
-
598 return tesSUCCESS;
-
599}
+
476 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
+
477 !isTesSuccess(err))
+
478 return err;
+
479
+
480 return preflight2(ctx);
+
481}
+
482
+
483TER
+
484PayChanClaim::preclaim(PreclaimContext const& ctx)
+
485{
+
486 if (!ctx.view.rules().enabled(featureCredentials))
+
487 return Transactor::preclaim(ctx);
+
488
+
489 if (auto const err =
+
490 credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
+
491 !isTesSuccess(err))
+
492 return err;
+
493
+
494 return tesSUCCESS;
+
495}
+
496
+
497TER
+
498PayChanClaim::doApply()
+
499{
+
500 Keylet const k(ltPAYCHAN, ctx_.tx[sfChannel]);
+
501 auto const slep = ctx_.view().peek(k);
+
502 if (!slep)
+
503 return tecNO_TARGET;
+
504
+
505 AccountID const src = (*slep)[sfAccount];
+
506 AccountID const dst = (*slep)[sfDestination];
+
507 AccountID const txAccount = ctx_.tx[sfAccount];
+
508
+
509 auto const curExpiration = (*slep)[~sfExpiration];
+
510 {
+
511 auto const cancelAfter = (*slep)[~sfCancelAfter];
+
512 auto const closeTime =
+
513 ctx_.view().info().parentCloseTime.time_since_epoch().count();
+
514 if ((cancelAfter && closeTime >= *cancelAfter) ||
+
515 (curExpiration && closeTime >= *curExpiration))
+
516 return closeChannel(
+
517 slep, ctx_.view(), k.key, ctx_.app.journal("View"));
+
518 }
+
519
+
520 if (txAccount != src && txAccount != dst)
+
521 return tecNO_PERMISSION;
+
522
+
523 if (ctx_.tx[~sfBalance])
+
524 {
+
525 auto const chanBalance = slep->getFieldAmount(sfBalance).xrp();
+
526 auto const chanFunds = slep->getFieldAmount(sfAmount).xrp();
+
527 auto const reqBalance = ctx_.tx[sfBalance].xrp();
+
528
+
529 if (txAccount == dst && !ctx_.tx[~sfSignature])
+
530 return temBAD_SIGNATURE;
+
531
+
532 if (ctx_.tx[~sfSignature])
+
533 {
+
534 PublicKey const pk((*slep)[sfPublicKey]);
+
535 if (ctx_.tx[sfPublicKey] != pk)
+
536 return temBAD_SIGNER;
+
537 }
+
538
+
539 if (reqBalance > chanFunds)
+
540 return tecUNFUNDED_PAYMENT;
+
541
+
542 if (reqBalance <= chanBalance)
+
543 // nothing requested
+
544 return tecUNFUNDED_PAYMENT;
+
545
+
546 auto const sled = ctx_.view().peek(keylet::account(dst));
+
547 if (!sled)
+
548 return tecNO_DST;
+
549
+
550 // Obeying the lsfDisallowXRP flag was a bug. Piggyback on
+
551 // featureDepositAuth to remove the bug.
+
552 bool const depositAuth{ctx_.view().rules().enabled(featureDepositAuth)};
+
553 if (!depositAuth &&
+
554 (txAccount == src && (sled->getFlags() & lsfDisallowXRP)))
+
555 return tecNO_TARGET;
+
556
+
557 if (depositAuth)
+
558 {
+
559 if (auto err = verifyDepositPreauth(
+
560 ctx_.tx, ctx_.view(), txAccount, dst, sled, ctx_.journal);
+
561 !isTesSuccess(err))
+
562 return err;
+
563 }
+
564
+
565 (*slep)[sfBalance] = ctx_.tx[sfBalance];
+
566 XRPAmount const reqDelta = reqBalance - chanBalance;
+
567 XRPL_ASSERT(
+
568 reqDelta >= beast::zero,
+
569 "ripple::PayChanClaim::doApply : minimum balance delta");
+
570 (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
+
571 ctx_.view().update(sled);
+
572 ctx_.view().update(slep);
+
573 }
+
574
+
575 if (ctx_.tx.getFlags() & tfRenew)
+
576 {
+
577 if (src != txAccount)
+
578 return tecNO_PERMISSION;
+
579 (*slep)[~sfExpiration] = std::nullopt;
+
580 ctx_.view().update(slep);
+
581 }
+
582
+
583 if (ctx_.tx.getFlags() & tfClose)
+
584 {
+
585 // Channel will close immediately if dry or the receiver closes
+
586 if (dst == txAccount || (*slep)[sfBalance] == (*slep)[sfAmount])
+
587 return closeChannel(
+
588 slep, ctx_.view(), k.key, ctx_.app.journal("View"));
+
589
+
590 auto const settleExpiration =
+
591 ctx_.view().info().parentCloseTime.time_since_epoch().count() +
+
592 (*slep)[sfSettleDelay];
+
593
+
594 if (!curExpiration || *curExpiration > settleExpiration)
+
595 {
+
596 (*slep)[~sfExpiration] = settleExpiration;
+
597 ctx_.view().update(slep);
+
598 }
+
599 }
600
-
601} // namespace ripple
+
601 return tesSUCCESS;
+
602}
+
603
+
604} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream fatal() const
Definition: Journal.h:352
virtual beast::Journal journal(std::string const &name)=0
@@ -692,8 +695,8 @@ $(function() {
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
static NotTEC preflight(PreflightContext const &ctx)
Definition: PayChan.cpp:420
-
static TER preclaim(PreclaimContext const &ctx)
Definition: PayChan.cpp:483
-
TER doApply() override
Definition: PayChan.cpp:496
+
static TER preclaim(PreclaimContext const &ctx)
Definition: PayChan.cpp:484
+
TER doApply() override
Definition: PayChan.cpp:498
static NotTEC preflight(PreflightContext const &ctx)
Definition: PayChan.cpp:175
TER doApply() override
Definition: PayChan.cpp:254
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: PayChan.cpp:169
@@ -718,8 +721,8 @@ $(function() {
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition: applySteps.h:59
Definition: XRPAmount.h:43
-
NotTEC checkFields(PreflightContext const &ctx)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:374
Keylet payChan(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition: Indexes.cpp:395
@@ -733,6 +736,7 @@ $(function() {
@ lsfDisallowXRP
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:1049
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
void serializePayChanAuthorization(Serializer &msg, uint256 const &key, XRPAmount const &amt)
@ tefBAD_LEDGER
Definition: TER.h:170
@ tefINTERNAL
Definition: TER.h:173
@@ -750,7 +754,6 @@ $(function() {
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:307
@ tecEXPIRED
Definition: TER.h:314
@ tesSUCCESS
Definition: TER.h:244
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
constexpr std::uint32_t tfClose
Definition: TxFlags.h:133
constexpr std::uint32_t tfPayChanClaimMask
Definition: TxFlags.h:134
@@ -775,8 +778,10 @@ $(function() {
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:79
ReadView const & view
Definition: Transactor.h:82
STTx const & tx
Definition: Transactor.h:85
+
beast::Journal const j
Definition: Transactor.h:87
State information when preflighting a tx.
Definition: Transactor.h:34
Rules const rules
Definition: Transactor.h:38
+
beast::Journal const j
Definition: Transactor.h:41
STTx const & tx
Definition: Transactor.h:37
T time_since_epoch(T... args)
diff --git a/Payment_8cpp_source.html b/Payment_8cpp_source.html index 9b3855ee22..204a7e7697 100644 --- a/Payment_8cpp_source.html +++ b/Payment_8cpp_source.html @@ -316,437 +316,455 @@ $(function() {
238 }
239 }
240
-
241 if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err))
-
242 return err;
-
243
-
244 return preflight2(ctx);
-
245}
-
246
-
247TER
-
248Payment::checkPermission(ReadView const& view, STTx const& tx)
-
249{
-
250 auto const delegate = tx[~sfDelegate];
-
251 if (!delegate)
-
252 return tesSUCCESS;
-
253
-
254 auto const delegateKey = keylet::delegate(tx[sfAccount], *delegate);
-
255 auto const sle = view.read(delegateKey);
-
256
-
257 if (!sle)
-
258 return tecNO_DELEGATE_PERMISSION;
-
259
-
260 if (checkTxPermission(sle, tx) == tesSUCCESS)
-
261 return tesSUCCESS;
-
262
-
263 std::unordered_set<GranularPermissionType> granularPermissions;
-
264 loadGranularPermission(sle, ttPAYMENT, granularPermissions);
-
265
-
266 auto const& dstAmount = tx.getFieldAmount(sfAmount);
-
267 auto const& amountIssue = dstAmount.issue();
-
268
-
269 if (granularPermissions.contains(PaymentMint) && !isXRP(amountIssue) &&
-
270 amountIssue.account == tx[sfAccount])
-
271 return tesSUCCESS;
-
272
-
273 if (granularPermissions.contains(PaymentBurn) && !isXRP(amountIssue) &&
-
274 amountIssue.account == tx[sfDestination])
-
275 return tesSUCCESS;
-
276
-
277 return tecNO_DELEGATE_PERMISSION;
-
278}
-
279
-
280TER
-
281Payment::preclaim(PreclaimContext const& ctx)
-
282{
-
283 // Ripple if source or destination is non-native or if there are paths.
-
284 std::uint32_t const txFlags = ctx.tx.getFlags();
-
285 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
-
286 auto const hasPaths = ctx.tx.isFieldPresent(sfPaths);
-
287 auto const sendMax = ctx.tx[~sfSendMax];
-
288
-
289 AccountID const dstAccountID(ctx.tx[sfDestination]);
-
290 STAmount const dstAmount(ctx.tx[sfAmount]);
-
291
-
292 auto const k = keylet::account(dstAccountID);
-
293 auto const sleDst = ctx.view.read(k);
-
294
-
295 if (!sleDst)
-
296 {
-
297 // Destination account does not exist.
-
298 if (!dstAmount.native())
-
299 {
-
300 JLOG(ctx.j.trace())
-
301 << "Delay transaction: Destination account does not exist.";
-
302
-
303 // Another transaction could create the account and then this
-
304 // transaction would succeed.
-
305 return tecNO_DST;
-
306 }
-
307 else if (ctx.view.open() && partialPaymentAllowed)
-
308 {
-
309 // You cannot fund an account with a partial payment.
-
310 // Make retry work smaller, by rejecting this.
-
311 JLOG(ctx.j.trace()) << "Delay transaction: Partial payment not "
-
312 "allowed to create account.";
-
313
-
314 // Another transaction could create the account and then this
-
315 // transaction would succeed.
-
316 return telNO_DST_PARTIAL;
-
317 }
-
318 else if (dstAmount < STAmount(ctx.view.fees().accountReserve(0)))
-
319 {
-
320 // accountReserve is the minimum amount that an account can have.
-
321 // Reserve is not scaled by load.
-
322 JLOG(ctx.j.trace())
-
323 << "Delay transaction: Destination account does not exist. "
-
324 << "Insufficent payment to create account.";
-
325
-
326 // TODO: dedupe
-
327 // Another transaction could create the account and then this
-
328 // transaction would succeed.
-
329 return tecNO_DST_INSUF_XRP;
-
330 }
-
331 }
-
332 else if (
-
333 (sleDst->getFlags() & lsfRequireDestTag) &&
-
334 !ctx.tx.isFieldPresent(sfDestinationTag))
-
335 {
-
336 // The tag is basically account-specific information we don't
-
337 // understand, but we can require someone to fill it in.
-
338
-
339 // We didn't make this test for a newly-formed account because there's
-
340 // no way for this field to be set.
-
341 JLOG(ctx.j.trace())
-
342 << "Malformed transaction: DestinationTag required.";
-
343
-
344 return tecDST_TAG_NEEDED;
-
345 }
-
346
-
347 // Payment with at least one intermediate step and uses transitive balances.
-
348 if ((hasPaths || sendMax || !dstAmount.native()) && ctx.view.open())
-
349 {
-
350 STPathSet const& paths = ctx.tx.getFieldPathSet(sfPaths);
-
351
-
352 if (paths.size() > MaxPathSize ||
-
353 std::any_of(paths.begin(), paths.end(), [](STPath const& path) {
-
354 return path.size() > MaxPathLength;
-
355 }))
-
356 {
-
357 return telBAD_PATH_COUNT;
-
358 }
-
359 }
-
360
-
361 if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]);
-
362 !isTesSuccess(err))
-
363 return err;
-
364
-
365 if (ctx.tx.isFieldPresent(sfDomainID))
-
366 {
-
367 if (!permissioned_dex::accountInDomain(
-
368 ctx.view, ctx.tx[sfAccount], ctx.tx[sfDomainID]))
-
369 return tecNO_PERMISSION;
-
370
-
371 if (!permissioned_dex::accountInDomain(
-
372 ctx.view, ctx.tx[sfDestination], ctx.tx[sfDomainID]))
-
373 return tecNO_PERMISSION;
-
374 }
-
375
-
376 return tesSUCCESS;
-
377}
-
378
-
379TER
-
380Payment::doApply()
-
381{
-
382 auto const deliverMin = ctx_.tx[~sfDeliverMin];
-
383
-
384 // Ripple if source or destination is non-native or if there are paths.
-
385 std::uint32_t const txFlags = ctx_.tx.getFlags();
-
386 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
-
387 bool const limitQuality = txFlags & tfLimitQuality;
-
388 bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect);
-
389 auto const hasPaths = ctx_.tx.isFieldPresent(sfPaths);
-
390 auto const sendMax = ctx_.tx[~sfSendMax];
-
391
-
392 AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination));
-
393 STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount));
-
394 bool const mptDirect = dstAmount.holds<MPTIssue>();
-
395 STAmount const maxSourceAmount =
-
396 getMaxSourceAmount(account_, dstAmount, sendMax);
-
397
-
398 JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText()
-
399 << " dstAmount=" << dstAmount.getFullText();
-
400
-
401 // Open a ledger for editing.
-
402 auto const k = keylet::account(dstAccountID);
-
403 SLE::pointer sleDst = view().peek(k);
-
404
-
405 if (!sleDst)
-
406 {
-
407 std::uint32_t const seqno{
-
408 view().rules().enabled(featureDeletableAccounts) ? view().seq()
-
409 : 1};
-
410
-
411 // Create the account.
-
412 sleDst = std::make_shared<SLE>(k);
-
413 sleDst->setAccountID(sfAccount, dstAccountID);
-
414 sleDst->setFieldU32(sfSequence, seqno);
-
415
-
416 view().insert(sleDst);
-
417 }
-
418 else
-
419 {
-
420 // Tell the engine that we are intending to change the destination
-
421 // account. The source account gets always charged a fee so it's always
-
422 // marked as modified.
-
423 view().update(sleDst);
-
424 }
-
425
-
426 // Determine whether the destination requires deposit authorization.
-
427 bool const depositAuth = view().rules().enabled(featureDepositAuth);
-
428 bool const reqDepositAuth =
-
429 sleDst->getFlags() & lsfDepositAuth && depositAuth;
-
430
-
431 bool const depositPreauth = view().rules().enabled(featureDepositPreauth);
+
241 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
+
242 !isTesSuccess(err))
+
243 return err;
+
244
+
245 return preflight2(ctx);
+
246}
+
247
+
248TER
+
249Payment::checkPermission(ReadView const& view, STTx const& tx)
+
250{
+
251 auto const delegate = tx[~sfDelegate];
+
252 if (!delegate)
+
253 return tesSUCCESS;
+
254
+
255 auto const delegateKey = keylet::delegate(tx[sfAccount], *delegate);
+
256 auto const sle = view.read(delegateKey);
+
257
+
258 if (!sle)
+
259 return tecNO_DELEGATE_PERMISSION;
+
260
+
261 if (checkTxPermission(sle, tx) == tesSUCCESS)
+
262 return tesSUCCESS;
+
263
+
264 std::unordered_set<GranularPermissionType> granularPermissions;
+
265 loadGranularPermission(sle, ttPAYMENT, granularPermissions);
+
266
+
267 auto const& dstAmount = tx.getFieldAmount(sfAmount);
+
268 auto const& amountIssue = dstAmount.issue();
+
269
+
270 if (granularPermissions.contains(PaymentMint) && !isXRP(amountIssue) &&
+
271 amountIssue.account == tx[sfAccount])
+
272 return tesSUCCESS;
+
273
+
274 if (granularPermissions.contains(PaymentBurn) && !isXRP(amountIssue) &&
+
275 amountIssue.account == tx[sfDestination])
+
276 return tesSUCCESS;
+
277
+
278 return tecNO_DELEGATE_PERMISSION;
+
279}
+
280
+
281TER
+
282Payment::preclaim(PreclaimContext const& ctx)
+
283{
+
284 // Ripple if source or destination is non-native or if there are paths.
+
285 std::uint32_t const txFlags = ctx.tx.getFlags();
+
286 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
+
287 auto const hasPaths = ctx.tx.isFieldPresent(sfPaths);
+
288 auto const sendMax = ctx.tx[~sfSendMax];
+
289
+
290 AccountID const dstAccountID(ctx.tx[sfDestination]);
+
291 STAmount const dstAmount(ctx.tx[sfAmount]);
+
292
+
293 auto const k = keylet::account(dstAccountID);
+
294 auto const sleDst = ctx.view.read(k);
+
295
+
296 if (!sleDst)
+
297 {
+
298 // Destination account does not exist.
+
299 if (!dstAmount.native())
+
300 {
+
301 JLOG(ctx.j.trace())
+
302 << "Delay transaction: Destination account does not exist.";
+
303
+
304 // Another transaction could create the account and then this
+
305 // transaction would succeed.
+
306 return tecNO_DST;
+
307 }
+
308 else if (ctx.view.open() && partialPaymentAllowed)
+
309 {
+
310 // You cannot fund an account with a partial payment.
+
311 // Make retry work smaller, by rejecting this.
+
312 JLOG(ctx.j.trace()) << "Delay transaction: Partial payment not "
+
313 "allowed to create account.";
+
314
+
315 // Another transaction could create the account and then this
+
316 // transaction would succeed.
+
317 return telNO_DST_PARTIAL;
+
318 }
+
319 else if (dstAmount < STAmount(ctx.view.fees().accountReserve(0)))
+
320 {
+
321 // accountReserve is the minimum amount that an account can have.
+
322 // Reserve is not scaled by load.
+
323 JLOG(ctx.j.trace())
+
324 << "Delay transaction: Destination account does not exist. "
+
325 << "Insufficent payment to create account.";
+
326
+
327 // TODO: dedupe
+
328 // Another transaction could create the account and then this
+
329 // transaction would succeed.
+
330 return tecNO_DST_INSUF_XRP;
+
331 }
+
332 }
+
333 else if (
+
334 (sleDst->getFlags() & lsfRequireDestTag) &&
+
335 !ctx.tx.isFieldPresent(sfDestinationTag))
+
336 {
+
337 // The tag is basically account-specific information we don't
+
338 // understand, but we can require someone to fill it in.
+
339
+
340 // We didn't make this test for a newly-formed account because there's
+
341 // no way for this field to be set.
+
342 JLOG(ctx.j.trace())
+
343 << "Malformed transaction: DestinationTag required.";
+
344
+
345 return tecDST_TAG_NEEDED;
+
346 }
+
347
+
348 // Payment with at least one intermediate step and uses transitive balances.
+
349 if ((hasPaths || sendMax || !dstAmount.native()) && ctx.view.open())
+
350 {
+
351 STPathSet const& paths = ctx.tx.getFieldPathSet(sfPaths);
+
352
+
353 if (paths.size() > MaxPathSize ||
+
354 std::any_of(paths.begin(), paths.end(), [](STPath const& path) {
+
355 return path.size() > MaxPathLength;
+
356 }))
+
357 {
+
358 return telBAD_PATH_COUNT;
+
359 }
+
360 }
+
361
+
362 if (auto const err =
+
363 credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
+
364 !isTesSuccess(err))
+
365 return err;
+
366
+
367 if (ctx.tx.isFieldPresent(sfDomainID))
+
368 {
+
369 if (!permissioned_dex::accountInDomain(
+
370 ctx.view, ctx.tx[sfAccount], ctx.tx[sfDomainID]))
+
371 return tecNO_PERMISSION;
+
372
+
373 if (!permissioned_dex::accountInDomain(
+
374 ctx.view, ctx.tx[sfDestination], ctx.tx[sfDomainID]))
+
375 return tecNO_PERMISSION;
+
376 }
+
377
+
378 return tesSUCCESS;
+
379}
+
380
+
381TER
+
382Payment::doApply()
+
383{
+
384 auto const deliverMin = ctx_.tx[~sfDeliverMin];
+
385
+
386 // Ripple if source or destination is non-native or if there are paths.
+
387 std::uint32_t const txFlags = ctx_.tx.getFlags();
+
388 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
+
389 bool const limitQuality = txFlags & tfLimitQuality;
+
390 bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect);
+
391 auto const hasPaths = ctx_.tx.isFieldPresent(sfPaths);
+
392 auto const sendMax = ctx_.tx[~sfSendMax];
+
393
+
394 AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination));
+
395 STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount));
+
396 bool const mptDirect = dstAmount.holds<MPTIssue>();
+
397 STAmount const maxSourceAmount =
+
398 getMaxSourceAmount(account_, dstAmount, sendMax);
+
399
+
400 JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText()
+
401 << " dstAmount=" << dstAmount.getFullText();
+
402
+
403 // Open a ledger for editing.
+
404 auto const k = keylet::account(dstAccountID);
+
405 SLE::pointer sleDst = view().peek(k);
+
406
+
407 if (!sleDst)
+
408 {
+
409 std::uint32_t const seqno{
+
410 view().rules().enabled(featureDeletableAccounts) ? view().seq()
+
411 : 1};
+
412
+
413 // Create the account.
+
414 sleDst = std::make_shared<SLE>(k);
+
415 sleDst->setAccountID(sfAccount, dstAccountID);
+
416 sleDst->setFieldU32(sfSequence, seqno);
+
417
+
418 view().insert(sleDst);
+
419 }
+
420 else
+
421 {
+
422 // Tell the engine that we are intending to change the destination
+
423 // account. The source account gets always charged a fee so it's always
+
424 // marked as modified.
+
425 view().update(sleDst);
+
426 }
+
427
+
428 // Determine whether the destination requires deposit authorization.
+
429 bool const depositAuth = view().rules().enabled(featureDepositAuth);
+
430 bool const reqDepositAuth =
+
431 sleDst->getFlags() & lsfDepositAuth && depositAuth;
432
-
433 bool const ripple =
-
434 (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
-
435
-
436 // If the destination has lsfDepositAuth set, then only direct XRP
-
437 // payments (no intermediate steps) are allowed to the destination.
-
438 if (!depositPreauth && ripple && reqDepositAuth)
-
439 return tecNO_PERMISSION;
-
440
-
441 if (ripple)
-
442 {
-
443 // Ripple payment with at least one intermediate step and uses
-
444 // transitive balances.
-
445
-
446 if (depositPreauth && depositAuth)
-
447 {
-
448 // If depositPreauth is enabled, then an account that requires
-
449 // authorization has two ways to get an IOU Payment in:
-
450 // 1. If Account == Destination, or
-
451 // 2. If Account is deposit preauthorized by destination.
-
452
-
453 if (auto err =
-
454 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
-
455 !isTesSuccess(err))
-
456 return err;
-
457 }
-
458
-
459 path::RippleCalc::Input rcInput;
-
460 rcInput.partialPaymentAllowed = partialPaymentAllowed;
-
461 rcInput.defaultPathsAllowed = defaultPathsAllowed;
-
462 rcInput.limitQuality = limitQuality;
-
463 rcInput.isLedgerOpen = view().open();
-
464
-
465 path::RippleCalc::Output rc;
-
466 {
-
467 PaymentSandbox pv(&view());
-
468 JLOG(j_.debug()) << "Entering RippleCalc in payment: "
-
469 << ctx_.tx.getTransactionID();
-
470 rc = path::RippleCalc::rippleCalculate(
-
471 pv,
-
472 maxSourceAmount,
-
473 dstAmount,
-
474 dstAccountID,
-
475 account_,
-
476 ctx_.tx.getFieldPathSet(sfPaths),
-
477 ctx_.tx[~sfDomainID],
-
478 ctx_.app.logs(),
-
479 &rcInput);
-
480 // VFALCO NOTE We might not need to apply, depending
-
481 // on the TER. But always applying *should*
-
482 // be safe.
-
483 pv.apply(ctx_.rawView());
-
484 }
-
485
-
486 // TODO: is this right? If the amount is the correct amount, was
-
487 // the delivered amount previously set?
-
488 if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount)
-
489 {
-
490 if (deliverMin && rc.actualAmountOut < *deliverMin)
-
491 rc.setResult(tecPATH_PARTIAL);
-
492 else
-
493 ctx_.deliver(rc.actualAmountOut);
-
494 }
-
495
-
496 auto terResult = rc.result();
-
497
-
498 // Because of its overhead, if RippleCalc
-
499 // fails with a retry code, claim a fee
-
500 // instead. Maybe the user will be more
-
501 // careful with their path spec next time.
-
502 if (isTerRetry(terResult))
-
503 terResult = tecPATH_DRY;
-
504 return terResult;
-
505 }
-
506 else if (mptDirect)
-
507 {
-
508 JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
-
509 auto const& mptIssue = dstAmount.get<MPTIssue>();
-
510
-
511 if (auto const ter = requireAuth(view(), mptIssue, account_);
-
512 ter != tesSUCCESS)
-
513 return ter;
-
514
-
515 if (auto const ter = requireAuth(view(), mptIssue, dstAccountID);
-
516 ter != tesSUCCESS)
-
517 return ter;
-
518
-
519 if (auto const ter =
-
520 canTransfer(view(), mptIssue, account_, dstAccountID);
-
521 ter != tesSUCCESS)
-
522 return ter;
-
523
-
524 if (auto err =
-
525 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
-
526 !isTesSuccess(err))
-
527 return err;
-
528
-
529 auto const& issuer = mptIssue.getIssuer();
+
433 bool const depositPreauth = view().rules().enabled(featureDepositPreauth);
+
434
+
435 bool const ripple =
+
436 (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
+
437
+
438 // If the destination has lsfDepositAuth set, then only direct XRP
+
439 // payments (no intermediate steps) are allowed to the destination.
+
440 if (!depositPreauth && ripple && reqDepositAuth)
+
441 return tecNO_PERMISSION;
+
442
+
443 if (ripple)
+
444 {
+
445 // Ripple payment with at least one intermediate step and uses
+
446 // transitive balances.
+
447
+
448 if (depositPreauth && depositAuth)
+
449 {
+
450 // If depositPreauth is enabled, then an account that requires
+
451 // authorization has two ways to get an IOU Payment in:
+
452 // 1. If Account == Destination, or
+
453 // 2. If Account is deposit preauthorized by destination.
+
454
+
455 if (auto err = verifyDepositPreauth(
+
456 ctx_.tx,
+
457 ctx_.view(),
+
458 account_,
+
459 dstAccountID,
+
460 sleDst,
+
461 ctx_.journal);
+
462 !isTesSuccess(err))
+
463 return err;
+
464 }
+
465
+
466 path::RippleCalc::Input rcInput;
+
467 rcInput.partialPaymentAllowed = partialPaymentAllowed;
+
468 rcInput.defaultPathsAllowed = defaultPathsAllowed;
+
469 rcInput.limitQuality = limitQuality;
+
470 rcInput.isLedgerOpen = view().open();
+
471
+
472 path::RippleCalc::Output rc;
+
473 {
+
474 PaymentSandbox pv(&view());
+
475 JLOG(j_.debug()) << "Entering RippleCalc in payment: "
+
476 << ctx_.tx.getTransactionID();
+
477 rc = path::RippleCalc::rippleCalculate(
+
478 pv,
+
479 maxSourceAmount,
+
480 dstAmount,
+
481 dstAccountID,
+
482 account_,
+
483 ctx_.tx.getFieldPathSet(sfPaths),
+
484 ctx_.tx[~sfDomainID],
+
485 ctx_.app.logs(),
+
486 &rcInput);
+
487 // VFALCO NOTE We might not need to apply, depending
+
488 // on the TER. But always applying *should*
+
489 // be safe.
+
490 pv.apply(ctx_.rawView());
+
491 }
+
492
+
493 // TODO: is this right? If the amount is the correct amount, was
+
494 // the delivered amount previously set?
+
495 if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount)
+
496 {
+
497 if (deliverMin && rc.actualAmountOut < *deliverMin)
+
498 rc.setResult(tecPATH_PARTIAL);
+
499 else
+
500 ctx_.deliver(rc.actualAmountOut);
+
501 }
+
502
+
503 auto terResult = rc.result();
+
504
+
505 // Because of its overhead, if RippleCalc
+
506 // fails with a retry code, claim a fee
+
507 // instead. Maybe the user will be more
+
508 // careful with their path spec next time.
+
509 if (isTerRetry(terResult))
+
510 terResult = tecPATH_DRY;
+
511 return terResult;
+
512 }
+
513 else if (mptDirect)
+
514 {
+
515 JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
+
516 auto const& mptIssue = dstAmount.get<MPTIssue>();
+
517
+
518 if (auto const ter = requireAuth(view(), mptIssue, account_);
+
519 ter != tesSUCCESS)
+
520 return ter;
+
521
+
522 if (auto const ter = requireAuth(view(), mptIssue, dstAccountID);
+
523 ter != tesSUCCESS)
+
524 return ter;
+
525
+
526 if (auto const ter =
+
527 canTransfer(view(), mptIssue, account_, dstAccountID);
+
528 ter != tesSUCCESS)
+
529 return ter;
530
-
531 // Transfer rate
-
532 Rate rate{QUALITY_ONE};
-
533 // Payment between the holders
-
534 if (account_ != issuer && dstAccountID != issuer)
-
535 {
-
536 // If globally/individually locked then
-
537 // - can't send between holders
-
538 // - holder can send back to issuer
-
539 // - issuer can send to holder
-
540 if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
-
541 return tecLOCKED;
+
531 if (auto err = verifyDepositPreauth(
+
532 ctx_.tx,
+
533 ctx_.view(),
+
534 account_,
+
535 dstAccountID,
+
536 sleDst,
+
537 ctx_.journal);
+
538 !isTesSuccess(err))
+
539 return err;
+
540
+
541 auto const& issuer = mptIssue.getIssuer();
542
-
543 // Get the rate for a payment between the holders.
-
544 rate = transferRate(view(), mptIssue.getMptID());
-
545 }
-
546
-
547 // Amount to deliver.
-
548 STAmount amountDeliver = dstAmount;
-
549 // Factor in the transfer rate.
-
550 // No rounding. It'll change once MPT integrated into DEX.
-
551 STAmount requiredMaxSourceAmount = multiply(dstAmount, rate);
-
552
-
553 // Send more than the account wants to pay or less than
-
554 // the account wants to deliver (if no SendMax).
-
555 // Adjust the amount to deliver.
-
556 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
-
557 {
-
558 requiredMaxSourceAmount = maxSourceAmount;
-
559 // No rounding. It'll change once MPT integrated into DEX.
-
560 amountDeliver = divide(maxSourceAmount, rate);
-
561 }
-
562
-
563 if (requiredMaxSourceAmount > maxSourceAmount ||
-
564 (deliverMin && amountDeliver < *deliverMin))
-
565 return tecPATH_PARTIAL;
-
566
-
567 PaymentSandbox pv(&view());
-
568 auto res = accountSend(
-
569 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
-
570 if (res == tesSUCCESS)
-
571 pv.apply(ctx_.rawView());
-
572 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
-
573 res = tecPATH_PARTIAL;
+
543 // Transfer rate
+
544 Rate rate{QUALITY_ONE};
+
545 // Payment between the holders
+
546 if (account_ != issuer && dstAccountID != issuer)
+
547 {
+
548 // If globally/individually locked then
+
549 // - can't send between holders
+
550 // - holder can send back to issuer
+
551 // - issuer can send to holder
+
552 if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
+
553 return tecLOCKED;
+
554
+
555 // Get the rate for a payment between the holders.
+
556 rate = transferRate(view(), mptIssue.getMptID());
+
557 }
+
558
+
559 // Amount to deliver.
+
560 STAmount amountDeliver = dstAmount;
+
561 // Factor in the transfer rate.
+
562 // No rounding. It'll change once MPT integrated into DEX.
+
563 STAmount requiredMaxSourceAmount = multiply(dstAmount, rate);
+
564
+
565 // Send more than the account wants to pay or less than
+
566 // the account wants to deliver (if no SendMax).
+
567 // Adjust the amount to deliver.
+
568 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
+
569 {
+
570 requiredMaxSourceAmount = maxSourceAmount;
+
571 // No rounding. It'll change once MPT integrated into DEX.
+
572 amountDeliver = divide(maxSourceAmount, rate);
+
573 }
574
-
575 return res;
-
576 }
-
577
-
578 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
-
579
-
580 // Direct XRP payment.
-
581
-
582 auto const sleSrc = view().peek(keylet::account(account_));
-
583 if (!sleSrc)
-
584 return tefINTERNAL;
-
585
-
586 // ownerCount is the number of entries in this ledger for this
-
587 // account that require a reserve.
-
588 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
+
575 if (requiredMaxSourceAmount > maxSourceAmount ||
+
576 (deliverMin && amountDeliver < *deliverMin))
+
577 return tecPATH_PARTIAL;
+
578
+
579 PaymentSandbox pv(&view());
+
580 auto res = accountSend(
+
581 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
+
582 if (res == tesSUCCESS)
+
583 pv.apply(ctx_.rawView());
+
584 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
+
585 res = tecPATH_PARTIAL;
+
586
+
587 return res;
+
588 }
589
-
590 // This is the total reserve in drops.
-
591 auto const reserve = view().fees().accountReserve(ownerCount);
-
592
-
593 // mPriorBalance is the balance on the sending account BEFORE the
-
594 // fees were charged. We want to make sure we have enough reserve
-
595 // to send. Allow final spend to use reserve for fee.
-
596 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
+
590 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
+
591
+
592 // Direct XRP payment.
+
593
+
594 auto const sleSrc = view().peek(keylet::account(account_));
+
595 if (!sleSrc)
+
596 return tefINTERNAL;
597
-
598 if (mPriorBalance < dstAmount.xrp() + mmm)
-
599 {
-
600 // Vote no. However the transaction might succeed, if applied in
-
601 // a different order.
-
602 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
-
603 << to_string(mPriorBalance) << " / "
-
604 << to_string(dstAmount.xrp() + mmm) << " ("
-
605 << to_string(reserve) << ")";
-
606
-
607 return tecUNFUNDED_PAYMENT;
-
608 }
+
598 // ownerCount is the number of entries in this ledger for this
+
599 // account that require a reserve.
+
600 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
+
601
+
602 // This is the total reserve in drops.
+
603 auto const reserve = view().fees().accountReserve(ownerCount);
+
604
+
605 // mPriorBalance is the balance on the sending account BEFORE the
+
606 // fees were charged. We want to make sure we have enough reserve
+
607 // to send. Allow final spend to use reserve for fee.
+
608 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
609
-
610 // Pseudo-accounts cannot receive payments, other than these native to
-
611 // their underlying ledger object - implemented in their respective
-
612 // transaction types. Note, this is not amendment-gated because all writes
-
613 // to pseudo-account discriminator fields **are** amendment gated, hence the
-
614 // behaviour of this check will always match the active amendments.
-
615 if (isPseudoAccount(sleDst))
-
616 return tecNO_PERMISSION;
-
617
-
618 // The source account does have enough money. Make sure the
-
619 // source account has authority to deposit to the destination.
-
620 if (depositAuth)
-
621 {
-
622 // If depositPreauth is enabled, then an account that requires
-
623 // authorization has three ways to get an XRP Payment in:
-
624 // 1. If Account == Destination, or
-
625 // 2. If Account is deposit preauthorized by destination, or
-
626 // 3. If the destination's XRP balance is
-
627 // a. less than or equal to the base reserve and
-
628 // b. the deposit amount is less than or equal to the base reserve,
-
629 // then we allow the deposit.
-
630 //
-
631 // Rule 3 is designed to keep an account from getting wedged
-
632 // in an unusable state if it sets the lsfDepositAuth flag and
-
633 // then consumes all of its XRP. Without the rule if an
-
634 // account with lsfDepositAuth set spent all of its XRP, it
-
635 // would be unable to acquire more XRP required to pay fees.
-
636 //
-
637 // We choose the base reserve as our bound because it is
-
638 // a small number that seldom changes but is always sufficient
-
639 // to get the account un-wedged.
-
640
-
641 // Get the base reserve.
-
642 XRPAmount const dstReserve{view().fees().accountReserve(0)};
-
643
-
644 if (dstAmount > dstReserve ||
-
645 sleDst->getFieldAmount(sfBalance) > dstReserve)
-
646 {
-
647 if (auto err =
-
648 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
-
649 !isTesSuccess(err))
-
650 return err;
-
651 }
-
652 }
-
653
-
654 // Do the arithmetic for the transfer and make the ledger change.
-
655 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
-
656 sleDst->setFieldAmount(
-
657 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
-
658
-
659 // Re-arm the password change fee if we can and need to.
-
660 if ((sleDst->getFlags() & lsfPasswordSpent))
-
661 sleDst->clearFlag(lsfPasswordSpent);
-
662
-
663 return tesSUCCESS;
-
664}
-
665
-
666} // namespace ripple
+
610 if (mPriorBalance < dstAmount.xrp() + mmm)
+
611 {
+
612 // Vote no. However the transaction might succeed, if applied in
+
613 // a different order.
+
614 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
+
615 << to_string(mPriorBalance) << " / "
+
616 << to_string(dstAmount.xrp() + mmm) << " ("
+
617 << to_string(reserve) << ")";
+
618
+
619 return tecUNFUNDED_PAYMENT;
+
620 }
+
621
+
622 // Pseudo-accounts cannot receive payments, other than these native to
+
623 // their underlying ledger object - implemented in their respective
+
624 // transaction types. Note, this is not amendment-gated because all writes
+
625 // to pseudo-account discriminator fields **are** amendment gated, hence the
+
626 // behaviour of this check will always match the active amendments.
+
627 if (isPseudoAccount(sleDst))
+
628 return tecNO_PERMISSION;
+
629
+
630 // The source account does have enough money. Make sure the
+
631 // source account has authority to deposit to the destination.
+
632 if (depositAuth)
+
633 {
+
634 // If depositPreauth is enabled, then an account that requires
+
635 // authorization has three ways to get an XRP Payment in:
+
636 // 1. If Account == Destination, or
+
637 // 2. If Account is deposit preauthorized by destination, or
+
638 // 3. If the destination's XRP balance is
+
639 // a. less than or equal to the base reserve and
+
640 // b. the deposit amount is less than or equal to the base reserve,
+
641 // then we allow the deposit.
+
642 //
+
643 // Rule 3 is designed to keep an account from getting wedged
+
644 // in an unusable state if it sets the lsfDepositAuth flag and
+
645 // then consumes all of its XRP. Without the rule if an
+
646 // account with lsfDepositAuth set spent all of its XRP, it
+
647 // would be unable to acquire more XRP required to pay fees.
+
648 //
+
649 // We choose the base reserve as our bound because it is
+
650 // a small number that seldom changes but is always sufficient
+
651 // to get the account un-wedged.
+
652
+
653 // Get the base reserve.
+
654 XRPAmount const dstReserve{view().fees().accountReserve(0)};
+
655
+
656 if (dstAmount > dstReserve ||
+
657 sleDst->getFieldAmount(sfBalance) > dstReserve)
+
658 {
+
659 if (auto err = verifyDepositPreauth(
+
660 ctx_.tx,
+
661 ctx_.view(),
+
662 account_,
+
663 dstAccountID,
+
664 sleDst,
+
665 ctx_.journal);
+
666 !isTesSuccess(err))
+
667 return err;
+
668 }
+
669 }
+
670
+
671 // Do the arithmetic for the transfer and make the ledger change.
+
672 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
+
673 sleDst->setFieldAmount(
+
674 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
+
675
+
676 // Re-arm the password change fee if we can and need to.
+
677 if ((sleDst->getFlags() & lsfPasswordSpent))
+
678 sleDst->clearFlag(lsfPasswordSpent);
+
679
+
680 return tesSUCCESS;
+
681}
+
682
+
683} // namespace ripple
T any_of(T... args)
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
virtual Logs & logs()=0
RawView & rawView()
Definition: ApplyContext.h:91
+
ApplyView & view()
Definition: ApplyContext.h:78
Application & app
Definition: ApplyContext.h:71
beast::Journal const journal
Definition: ApplyContext.h:75
STTx const & tx
Definition: ApplyContext.h:72
@@ -761,9 +779,9 @@ $(function() {
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
static std::size_t const MaxPathSize
Definition: Payment.h:30
-
static TER checkPermission(ReadView const &view, STTx const &tx)
Definition: Payment.cpp:248
-
TER doApply() override
Definition: Payment.cpp:380
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Payment.cpp:281
+
static TER checkPermission(ReadView const &view, STTx const &tx)
Definition: Payment.cpp:249
+
TER doApply() override
Definition: Payment.cpp:382
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Payment.cpp:282
static NotTEC preflight(PreflightContext const &ctx)
Definition: Payment.cpp:69
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: Payment.cpp:36
A view into a ledger.
Definition: ReadView.h:52
@@ -809,8 +827,8 @@ $(function() {
T contains(T... args)
T max(T... args)
-
NotTEC checkFields(PreflightContext const &ctx)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
NotTEC checkFields(STTx const &tx, beast::Journal j)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition: Indexes.cpp:465
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
bool accountInDomain(ReadView const &view, AccountID const &account, Domain const &domainID)
@@ -831,6 +849,7 @@ $(function() {
@ lsfDepositAuth
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:53
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
+
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
Definition: View.cpp:2509
@ tefINTERNAL
Definition: TER.h:173
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:108
@@ -850,7 +869,6 @@ $(function() {
bool isTerRetry(TER x) noexcept
Definition: TER.h:668
constexpr std::uint32_t tfNoRippleDirect
Definition: TxFlags.h:107
@ tesSUCCESS
Definition: TER.h:244
-
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
bool isTesSuccess(TER x) noexcept
Definition: TER.h:674
constexpr std::uint32_t tfPaymentMask
Definition: TxFlags.h:110
constexpr std::uint32_t tfLimitQuality
Definition: TxFlags.h:109
diff --git a/Payment_8h_source.html b/Payment_8h_source.html index c14cb68388..996d1353b3 100644 --- a/Payment_8h_source.html +++ b/Payment_8h_source.html @@ -139,10 +139,10 @@ $(function() {
State information when applying a tx.
Definition: ApplyContext.h:37
Definition: Payment.h:28
static std::size_t const MaxPathSize
Definition: Payment.h:30
-
static TER checkPermission(ReadView const &view, STTx const &tx)
Definition: Payment.cpp:248
+
static TER checkPermission(ReadView const &view, STTx const &tx)
Definition: Payment.cpp:249
Payment(ApplyContext &ctx)
Definition: Payment.h:38
-
TER doApply() override
Definition: Payment.cpp:380
-
static TER preclaim(PreclaimContext const &ctx)
Definition: Payment.cpp:281
+
TER doApply() override
Definition: Payment.cpp:382
+
static TER preclaim(PreclaimContext const &ctx)
Definition: Payment.cpp:282
static NotTEC preflight(PreflightContext const &ctx)
Definition: Payment.cpp:69
static constexpr ConsequencesFactoryType ConsequencesFactory
Definition: Payment.h:36
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition: Payment.cpp:36
diff --git a/PeerImp_8cpp_source.html b/PeerImp_8cpp_source.html index 394e7bdb8f..f35d15e8c6 100644 --- a/PeerImp_8cpp_source.html +++ b/PeerImp_8cpp_source.html @@ -2988,12 +2988,12 @@ $(function() {
2912 if (checkSignature)
2913 {
2914 // Check the signature before handing off to the job queue.
-
2915 if (auto [valid, validReason] = checkValidity(
+
2915 if (auto [valid, validReason] = checkValidity(
2916 app_.getHashRouter(),
2917 *stx,
2918 app_.getLedgerMaster().getValidatedRules(),
2919 app_.config());
-
2920 valid != Validity::Valid)
+
2920 valid != Validity::Valid)
2921 {
2922 if (!validReason.empty())
2923 {
@@ -3855,7 +3855,7 @@ $(function() {
@ sendqIntervals
How many timer intervals a sendq has to stay large before we disconnect.
@ sendQueueLogFreq
How often to log send queue size.
Compressed
Definition: Compression.h:37
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
auto measureDurationAndLog(Func &&func, std::string const &actionDescription, std::chrono::duration< Rep, Period > maxDelay, beast::Journal const &journal)
Definition: PerfLog.h:187
static constexpr std::size_t MAX_TX_QUEUE_SIZE
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
diff --git a/PermissionedDomainSet_8cpp_source.html b/PermissionedDomainSet_8cpp_source.html index 164b5d9f21..4bd30d0017 100644 --- a/PermissionedDomainSet_8cpp_source.html +++ b/PermissionedDomainSet_8cpp_source.html @@ -258,8 +258,8 @@ $(function() {
AccountID const account_
Definition: Transactor.h:143
ApplyView & view()
Definition: Transactor.h:159
ApplyContext & ctx_
Definition: Transactor.h:140
-
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
-
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
+
NotTEC checkArray(STArray const &credentials, unsigned maxSize, beast::Journal j)
+
std::set< std::pair< AccountID, Slice > > makeSorted(STArray const &credentials)
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
Definition: Indexes.cpp:570
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:374
diff --git a/STAmount_8cpp_source.html b/STAmount_8cpp_source.html index 57c8624aca..f7c03be003 100644 --- a/STAmount_8cpp_source.html +++ b/STAmount_8cpp_source.html @@ -175,9 +175,9 @@ $(function() {
97
98//------------------------------------------------------------------------------
99static std::int64_t
-
100getInt64Value(STAmount const& amount, bool valid, char const* error)
+
100getInt64Value(STAmount const& amount, bool valid, char const* error)
101{
-
102 if (!valid)
+
102 if (!valid)
103 Throw<std::runtime_error>(error);
104 XRPL_ASSERT(
105 amount.exponent() == 0, "ripple::getInt64Value : exponent is zero");
@@ -1928,7 +1928,7 @@ $(function() {
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
unsigned int UInt
Definition: json_forwards.h:27
Definition: base_uint.h:662
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:118
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
Definition: STAmount.cpp:1471
diff --git a/StrandFlow_8h_source.html b/StrandFlow_8h_source.html index 9de03b8f3c..43c88bd621 100644 --- a/StrandFlow_8h_source.html +++ b/StrandFlow_8h_source.html @@ -330,10 +330,10 @@ $(function() {
266 EitherAmount stepIn(*strand[0]->cachedIn());
267 for (auto i = 0; i < s; ++i)
268 {
-
269 bool valid;
-
270 std::tie(valid, stepIn) =
+
269 bool valid;
+
270 std::tie(valid, stepIn) =
271 strand[i]->validFwd(checkSB, checkAfView, stepIn);
-
272 if (!valid)
+
272 if (!valid)
273 {
274 JLOG(j.warn())
275 << "Strand re-execute check failed. Step: " << i;
@@ -955,7 +955,7 @@ $(function() {
T make_optional(T... args)
T min(T... args)
T move(T... args)
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:274
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
static auto sum(TCollection const &col)
Definition: BookStep.cpp:1005
diff --git a/TaggedCache_8h_source.html b/TaggedCache_8h_source.html index 0fa7c30f72..2efadb3a4e 100644 --- a/TaggedCache_8h_source.html +++ b/TaggedCache_8h_source.html @@ -176,7 +176,7 @@ $(function() {
115 sweep();
116
117 bool
-
118 del(key_type const& key, bool valid);
+
118 del(key_type const& key, bool valid);
119
120public:
134 template <class R>
@@ -449,7 +449,7 @@ $(function() {
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition: tokens.cpp:156
diff --git a/ValidatorSite_8cpp_source.html b/ValidatorSite_8cpp_source.html index 9082bb9973..fc4e7501a6 100644 --- a/ValidatorSite_8cpp_source.html +++ b/ValidatorSite_8cpp_source.html @@ -464,24 +464,24 @@ $(function() {
386 return body;
387 }();
388
-
389 auto const [valid, version, blobs] = [&body]() {
+
389 auto const [valid, version, blobs] = [&body]() {
390 // Check the easy fields first
-
391 bool valid = body.isObject() && body.isMember(jss::manifest) &&
+
391 bool valid = body.isObject() && body.isMember(jss::manifest) &&
392 body[jss::manifest].isString() && body.isMember(jss::version) &&
393 body[jss::version].isInt();
394 // Check the version-specific blob & signature fields
395 std::uint32_t version;
396 std::vector<ValidatorBlobInfo> blobs;
-
397 if (valid)
+
397 if (valid)
398 {
399 version = body[jss::version].asUInt();
400 blobs = ValidatorList::parseBlobs(version, body);
-
401 valid = !blobs.empty();
+
401 valid = !blobs.empty();
402 }
-
403 return std::make_tuple(valid, version, blobs);
+
403 return std::make_tuple(valid, version, blobs);
404 }();
405
-
406 if (!valid)
+
406 if (!valid)
407 {
408 JLOG(j_.warn()) << "Missing fields in JSON response from "
409 << sites_[siteIdx].activeResource->uri;
@@ -852,7 +852,7 @@ $(function() {
T min_element(T... args)
@ arrayValue
array value (ordered list)
Definition: json_value.h:45
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
boost::beast::http::response< boost::beast::http::string_body > response_type
Definition: Work.h:31
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
@ unsupported_version
List version is not supported.
diff --git a/VaultDeposit_8cpp_source.html b/VaultDeposit_8cpp_source.html index 6c2bafa463..f165e34c3c 100644 --- a/VaultDeposit_8cpp_source.html +++ b/VaultDeposit_8cpp_source.html @@ -381,7 +381,7 @@ $(function() {
TER doApply() override
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
-
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
+
TER validDomain(ReadView const &view, uint256 domainID, AccountID const &subject)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition: Indexes.cpp:540
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition: Indexes.cpp:526
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition: Indexes.cpp:564
diff --git a/View_8cpp_source.html b/View_8cpp_source.html index 0e5efeb35b..61fba8f674 100644 --- a/View_8cpp_source.html +++ b/View_8cpp_source.html @@ -3265,7 +3265,7 @@ $(function() {
TER cleanupOnAccountDelete(ApplyView &view, Keylet const &ownerDirKeylet, EntryDeleter const &deleter, beast::Journal j, std::optional< uint16_t > maxNodesToDelete)
Definition: View.cpp:2529
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Definition: View.cpp:655
Number root(Number f, unsigned d)
Definition: Number.cpp:636
-
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
+
TER verifyValidDomain(ApplyView &view, AccountID const &account, uint256 domainID, beast::Journal j)
STAmount assetsToSharesDeposit(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &assets)
Definition: View.cpp:2684
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition: View.cpp:175
static TER rippleSendIOU(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j, WaiveTransferFee waiveFee)
Definition: View.cpp:1686
diff --git a/apply__test_8cpp_source.html b/apply__test_8cpp_source.html index 866730d967..9333a203f2 100644 --- a/apply__test_8cpp_source.html +++ b/apply__test_8cpp_source.html @@ -136,14 +136,14 @@ $(function() {
58 test::jtx::supported_amendments() -
59 featureRequireFullyCanonicalSig);
60
-
61 Validity valid = checkValidity(
+
61 Validity valid = checkValidity(
62 no_fully_canonical.app().getHashRouter(),
63 tx,
64 no_fully_canonical.current()->rules(),
65 no_fully_canonical.app().config())
66 .first;
67
-
68 if (valid != Validity::Valid)
+
68 if (valid != Validity::Valid)
69 fail("Non-Fully canoncial signature was not permitted");
70 }
71
@@ -151,13 +151,13 @@ $(function() {
73 test::jtx::Env fully_canonical(
74 *this, test::jtx::supported_amendments());
75
-
76 Validity valid = checkValidity(
+
76 Validity valid = checkValidity(
77 fully_canonical.app().getHashRouter(),
78 tx,
79 fully_canonical.current()->rules(),
80 fully_canonical.app().config())
81 .first;
-
82 if (valid == Validity::Valid)
+
82 if (valid == Validity::Valid)
83 fail("Non-Fully canoncial signature was permitted");
84 }
85
@@ -183,7 +183,7 @@ $(function() {
A transaction testing environment.
Definition: Env.h:121
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
Application & app()
Definition: Env.h:261
-
TER valid(PreclaimContext const &ctx, AccountID const &src)
+
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
FeatureBitset supported_amendments()
Definition: Env.h:74
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
diff --git a/classripple_1_1DeleteAccount.html b/classripple_1_1DeleteAccount.html index ea5ab5b5ac..3ec05433e4 100644 --- a/classripple_1_1DeleteAccount.html +++ b/classripple_1_1DeleteAccount.html @@ -376,7 +376,7 @@ Static Private Member Functions
-

Definition at line 68 of file DeleteAccount.cpp.

+

Definition at line 69 of file DeleteAccount.cpp.

@@ -404,7 +404,7 @@ Static Private Member Functions
-

Definition at line 230 of file DeleteAccount.cpp.

+

Definition at line 231 of file DeleteAccount.cpp.

@@ -433,7 +433,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 362 of file DeleteAccount.cpp.

+

Definition at line 364 of file DeleteAccount.cpp.

diff --git a/classripple_1_1EscrowCancel.html b/classripple_1_1EscrowCancel.html index d98e977ecd..1e84d3c209 100644 --- a/classripple_1_1EscrowCancel.html +++ b/classripple_1_1EscrowCancel.html @@ -338,7 +338,7 @@ Static Private Member Functions
-

Definition at line 1198 of file Escrow.cpp.

+

Definition at line 1201 of file Escrow.cpp.

@@ -366,7 +366,7 @@ Static Private Member Functions
-

Definition at line 1267 of file Escrow.cpp.

+

Definition at line 1270 of file Escrow.cpp.

@@ -395,7 +395,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 1295 of file Escrow.cpp.

+

Definition at line 1298 of file Escrow.cpp.

diff --git a/classripple_1_1EscrowFinish.html b/classripple_1_1EscrowFinish.html index fa08973594..e56b146a71 100644 --- a/classripple_1_1EscrowFinish.html +++ b/classripple_1_1EscrowFinish.html @@ -376,7 +376,7 @@ Static Private Member Functions
-

Definition at line 682 of file Escrow.cpp.

+

Definition at line 683 of file Escrow.cpp.

@@ -404,7 +404,7 @@ Static Private Member Functions
-

Definition at line 760 of file Escrow.cpp.

+

Definition at line 761 of file Escrow.cpp.

@@ -433,7 +433,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 1013 of file Escrow.cpp.

+

Definition at line 1015 of file Escrow.cpp.

diff --git a/classripple_1_1LedgerHistory.html b/classripple_1_1LedgerHistory.html index dea16bfca6..4f525850e4 100644 --- a/classripple_1_1LedgerHistory.html +++ b/classripple_1_1LedgerHistory.html @@ -184,7 +184,7 @@ Private Types - +

Private Member Functions

void handleMismatch (LedgerHash const &built, LedgerHash const &valid, std::optional< uint256 > const &builtConsensusHash, std::optional< uint256 > const &validatedConsensusHash, Json::Value const &consensus)
void handleMismatch (LedgerHash const &built, LedgerHash const &valid, std::optional< uint256 > const &builtConsensusHash, std::optional< uint256 > const &validatedConsensusHash, Json::Value const &consensus)
 Log details in the case where we build one ledger but validate a different one. More...
 
diff --git a/classripple_1_1PayChanClaim.html b/classripple_1_1PayChanClaim.html index 03961e8acb..81ff07a2ee 100644 --- a/classripple_1_1PayChanClaim.html +++ b/classripple_1_1PayChanClaim.html @@ -366,7 +366,7 @@ Static Private Member Functions
-

Definition at line 483 of file PayChan.cpp.

+

Definition at line 484 of file PayChan.cpp.

@@ -395,7 +395,7 @@ Static Private Member Functions

Implements ripple::Transactor.

-

Definition at line 496 of file PayChan.cpp.

+

Definition at line 498 of file PayChan.cpp.

diff --git a/classripple_1_1Payment.html b/classripple_1_1Payment.html index f32d31a61a..6050e9b360 100644 --- a/classripple_1_1Payment.html +++ b/classripple_1_1Payment.html @@ -414,7 +414,7 @@ Static Private Attributes
-

Definition at line 248 of file Payment.cpp.

+

Definition at line 249 of file Payment.cpp.

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

Definition at line 281 of file Payment.cpp.

+

Definition at line 282 of file Payment.cpp.

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

Implements ripple::Transactor.

-

Definition at line 380 of file Payment.cpp.

+

Definition at line 382 of file Payment.cpp.

diff --git a/classripple_1_1TaggedCache.html b/classripple_1_1TaggedCache.html index 487873f7cf..09c4b4be2d 100644 --- a/classripple_1_1TaggedCache.html +++ b/classripple_1_1TaggedCache.html @@ -169,7 +169,7 @@ Public Member Functions   void sweep ()   -bool del (key_type const &key, bool valid) +bool del (key_type const &key, bool valid)   template<class R > bool canonicalize (key_type const &key, SharedPointerType &data, R &&replaceCallback) diff --git a/namespacemembers_c.html b/namespacemembers_c.html index 02ea905ea6..13c616e6f8 100644 --- a/namespacemembers_c.html +++ b/namespacemembers_c.html @@ -124,7 +124,7 @@ $(function() {
  • CheckCreate : ripple
  • checkExpired() : ripple::credentials
  • checkFee() : ripple::RPC
  • -
  • checkFields() : ripple::credentials
  • +
  • checkFields() : ripple::credentials
  • checkFreeze() : ripple
  • checkIdlePeers : ripple::Tuning
  • checkMetrics() : ripple::test::jtx
  • diff --git a/namespacemembers_func_c.html b/namespacemembers_func_c.html index dbf50f31af..1f6ca938e7 100644 --- a/namespacemembers_func_c.html +++ b/namespacemembers_func_c.html @@ -111,7 +111,7 @@ $(function() {
  • checkConsensusReached() : ripple
  • checkExpired() : ripple::credentials
  • checkFee() : ripple::RPC
  • -
  • checkFields() : ripple::credentials
  • +
  • checkFields() : ripple::credentials
  • checkFreeze() : ripple
  • checkMetrics() : ripple::test::jtx
  • checkMultiSignFields() : ripple::RPC::detail
  • diff --git a/namespacemembers_func_v.html b/namespacemembers_func_v.html index d6790bad01..8cc0ed862a 100644 --- a/namespacemembers_func_v.html +++ b/namespacemembers_func_v.html @@ -73,7 +73,7 @@ $(function() {

    - v -