rippled
Transactor.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/main/Application.h>
21 #include <ripple/app/misc/LoadFeeTrack.h>
22 #include <ripple/app/tx/apply.h>
23 #include <ripple/app/tx/impl/SignerEntries.h>
24 #include <ripple/app/tx/impl/Transactor.h>
25 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
26 #include <ripple/basics/Log.h>
27 #include <ripple/basics/contract.h>
28 #include <ripple/core/Config.h>
29 #include <ripple/json/to_string.h>
30 #include <ripple/ledger/View.h>
31 #include <ripple/protocol/Feature.h>
32 #include <ripple/protocol/Indexes.h>
33 #include <ripple/protocol/Protocol.h>
34 #include <ripple/protocol/STAccount.h>
35 #include <ripple/protocol/UintTypes.h>
36 
37 namespace ripple {
38 
40 NotTEC
42 {
43  uint32_t const nodeNID = ctx.app.config().NETWORK_ID;
44  std::optional<uint32_t> const txNID = ctx.tx[~sfNetworkID];
45 
46  if (nodeNID <= 1024)
47  {
48  // legacy networks have IDs 1024 and below. These networks cannot
49  // specify NetworkID in txn
50  if (txNID)
52  }
53  else
54  {
55  // new networks both require the field to be present and require it to
56  // match
57  if (!txNID)
59 
60  if (*txNID != nodeNID)
61  return telWRONG_NETWORK;
62  }
63 
64  auto const txID = ctx.tx.getTransactionID();
65 
66  if (txID == beast::zero)
67  {
68  JLOG(ctx.j.warn())
69  << "applyTransaction: transaction id may not be zero";
70  return temINVALID;
71  }
72 
73  return tesSUCCESS;
74 }
75 
77 NotTEC
79 {
80  // This is inappropriate in preflight0, because only Change transactions
81  // skip this function, and those do not allow an sfTicketSequence field.
84  {
85  return temMALFORMED;
86  }
87 
88  auto const ret = preflight0(ctx);
89  if (!isTesSuccess(ret))
90  return ret;
91 
92  auto const id = ctx.tx.getAccountID(sfAccount);
93  if (id == beast::zero)
94  {
95  JLOG(ctx.j.warn()) << "preflight1: bad account id";
96  return temBAD_SRC_ACCOUNT;
97  }
98 
99  // No point in going any further if the transaction fee is malformed.
100  auto const fee = ctx.tx.getFieldAmount(sfFee);
101  if (!fee.native() || fee.negative() || !isLegalAmount(fee.xrp()))
102  {
103  JLOG(ctx.j.debug()) << "preflight1: invalid fee";
104  return temBAD_FEE;
105  }
106 
107  auto const spk = ctx.tx.getSigningPubKey();
108 
109  if (!spk.empty() && !publicKeyType(makeSlice(spk)))
110  {
111  JLOG(ctx.j.debug()) << "preflight1: invalid signing key";
112  return temBAD_SIGNATURE;
113  }
114 
115  // An AccountTxnID field constrains transaction ordering more than the
116  // Sequence field. Tickets, on the other hand, reduce ordering
117  // constraints. Because Tickets and AccountTxnID work against one
118  // another the combination is unsupported and treated as malformed.
119  //
120  // We return temINVALID for such transactions.
121  if (ctx.tx.getSeqProxy().isTicket() &&
123  return temINVALID;
124 
125  return tesSUCCESS;
126 }
127 
129 NotTEC
131 {
132  auto const sigValid = checkValidity(
133  ctx.app.getHashRouter(), ctx.tx, ctx.rules, ctx.app.config());
134  if (sigValid.first == Validity::SigBad)
135  {
136  JLOG(ctx.j.debug()) << "preflight2: bad signature. " << sigValid.second;
137  return temINVALID;
138  }
139  return tesSUCCESS;
140 }
141 
142 //------------------------------------------------------------------------------
143 
145  Application& app_,
146  STTx const& tx_,
147  Rules const& rules_,
148  ApplyFlags flags_,
149  beast::Journal j_)
150  : app(app_), tx(tx_), rules(rules_), flags(flags_), j(j_)
151 {
152 }
153 
154 //------------------------------------------------------------------------------
155 
157  : ctx_(ctx), j_(ctx.journal), account_(ctx.tx.getAccountID(sfAccount))
158 {
159 }
160 
161 XRPAmount
163 {
164  // Returns the fee in fee units.
165 
166  // The computation has two parts:
167  // * The base fee, which is the same for most transactions.
168  // * The additional cost of each multisignature on the transaction.
169  XRPAmount const baseFee = view.fees().base;
170 
171  // Each signer adds one more baseFee to the minimum required fee
172  // for the transaction.
173  std::size_t const signerCount =
175 
176  return baseFee + (signerCount * baseFee);
177 }
178 
179 XRPAmount
181  Application& app,
182  XRPAmount baseFee,
183  Fees const& fees,
184  ApplyFlags flags)
185 {
186  return scaleFeeLoad(baseFee, app.getFeeTrack(), fees, flags & tapUNLIMITED);
187 }
188 
189 TER
191 {
192  if (!ctx.tx[sfFee].native())
193  return temBAD_FEE;
194 
195  auto const feePaid = ctx.tx[sfFee].xrp();
196  if (!isLegalAmount(feePaid) || feePaid < beast::zero)
197  return temBAD_FEE;
198 
199  // Only check fee is sufficient when the ledger is open.
200  if (ctx.view.open())
201  {
202  auto const feeDue =
203  minimumFee(ctx.app, baseFee, ctx.view.fees(), ctx.flags);
204 
205  if (feePaid < feeDue)
206  {
207  JLOG(ctx.j.trace())
208  << "Insufficient fee paid: " << to_string(feePaid) << "/"
209  << to_string(feeDue);
210  return telINSUF_FEE_P;
211  }
212  }
213 
214  if (feePaid == beast::zero)
215  return tesSUCCESS;
216 
217  auto const id = ctx.tx.getAccountID(sfAccount);
218  auto const sle = ctx.view.read(keylet::account(id));
219  if (!sle)
220  return terNO_ACCOUNT;
221 
222  auto const balance = (*sle)[sfBalance].xrp();
223 
224  if (balance < feePaid)
225  {
226  JLOG(ctx.j.trace()) << "Insufficient balance:"
227  << " balance=" << to_string(balance)
228  << " paid=" << to_string(feePaid);
229 
230  if ((balance > beast::zero) && !ctx.view.open())
231  {
232  // Closed ledger, non-zero balance, less than fee
233  return tecINSUFF_FEE;
234  }
235 
236  return terINSUF_FEE_B;
237  }
238 
239  return tesSUCCESS;
240 }
241 
242 TER
244 {
245  auto const feePaid = ctx_.tx[sfFee].xrp();
246 
247  auto const sle = view().peek(keylet::account(account_));
248  if (!sle)
249  return tefINTERNAL;
250 
251  // Deduct the fee, so it's not available during the transaction.
252  // Will only write the account back if the transaction succeeds.
253 
254  mSourceBalance -= feePaid;
255  sle->setFieldAmount(sfBalance, mSourceBalance);
256 
257  // VFALCO Should we call view().rawDestroyXRP() here as well?
258 
259  return tesSUCCESS;
260 }
261 
262 NotTEC
264  ReadView const& view,
265  STTx const& tx,
266  beast::Journal j)
267 {
268  auto const id = tx.getAccountID(sfAccount);
269 
270  auto const sle = view.read(keylet::account(id));
271 
272  if (!sle)
273  {
274  JLOG(j.trace())
275  << "applyTransaction: delay: source account does not exist "
276  << toBase58(id);
277  return terNO_ACCOUNT;
278  }
279 
280  SeqProxy const t_seqProx = tx.getSeqProxy();
281  SeqProxy const a_seq = SeqProxy::sequence((*sle)[sfSequence]);
282 
283  if (t_seqProx.isSeq())
284  {
287  {
288  JLOG(j.trace()) << "applyTransaction: has both a TicketSequence "
289  "and a non-zero Sequence number";
290  return temSEQ_AND_TICKET;
291  }
292  if (t_seqProx != a_seq)
293  {
294  if (a_seq < t_seqProx)
295  {
296  JLOG(j.trace())
297  << "applyTransaction: has future sequence number "
298  << "a_seq=" << a_seq << " t_seq=" << t_seqProx;
299  return terPRE_SEQ;
300  }
301  // It's an already-used sequence number.
302  JLOG(j.trace()) << "applyTransaction: has past sequence number "
303  << "a_seq=" << a_seq << " t_seq=" << t_seqProx;
304  return tefPAST_SEQ;
305  }
306  }
307  else if (t_seqProx.isTicket())
308  {
309  // Bypass the type comparison. Apples and oranges.
310  if (a_seq.value() <= t_seqProx.value())
311  {
312  // If the Ticket number is greater than or equal to the
313  // account sequence there's the possibility that the
314  // transaction to create the Ticket has not hit the ledger
315  // yet. Allow a retry.
316  JLOG(j.trace()) << "applyTransaction: has future ticket id "
317  << "a_seq=" << a_seq << " t_seq=" << t_seqProx;
318  return terPRE_TICKET;
319  }
320 
321  // Transaction can never succeed if the Ticket is not in the ledger.
322  if (!view.exists(keylet::ticket(id, t_seqProx)))
323  {
324  JLOG(j.trace())
325  << "applyTransaction: ticket already used or never created "
326  << "a_seq=" << a_seq << " t_seq=" << t_seqProx;
327  return tefNO_TICKET;
328  }
329  }
330 
331  return tesSUCCESS;
332 }
333 
334 NotTEC
336 {
337  auto const id = ctx.tx.getAccountID(sfAccount);
338 
339  auto const sle = ctx.view.read(keylet::account(id));
340 
341  if (!sle)
342  {
343  JLOG(ctx.j.trace())
344  << "applyTransaction: delay: source account does not exist "
345  << toBase58(id);
346  return terNO_ACCOUNT;
347  }
348 
349  if (ctx.tx.isFieldPresent(sfAccountTxnID) &&
350  (sle->getFieldH256(sfAccountTxnID) !=
352  return tefWRONG_PRIOR;
353 
355  (ctx.view.seq() > ctx.tx.getFieldU32(sfLastLedgerSequence)))
356  return tefMAX_LEDGER;
357 
358  if (ctx.view.txExists(ctx.tx.getTransactionID()))
359  return tefALREADY;
360 
361  return tesSUCCESS;
362 }
363 
364 TER
366 {
367  assert(sleAccount);
368  SeqProxy const seqProx = ctx_.tx.getSeqProxy();
369  if (seqProx.isSeq())
370  {
371  // Note that if this transaction is a TicketCreate, then
372  // the transaction will modify the account root sfSequence
373  // yet again.
374  sleAccount->setFieldU32(sfSequence, seqProx.value() + 1);
375  return tesSUCCESS;
376  }
377  return ticketDelete(
378  view(), account_, getTicketIndex(account_, seqProx), j_);
379 }
380 
381 // Remove a single Ticket from the ledger.
382 TER
384  ApplyView& view,
385  AccountID const& account,
386  uint256 const& ticketIndex,
387  beast::Journal j)
388 {
389  // Delete the Ticket, adjust the account root ticket count, and
390  // reduce the owner count.
391  SLE::pointer const sleTicket = view.peek(keylet::ticket(ticketIndex));
392  if (!sleTicket)
393  {
394  JLOG(j.fatal()) << "Ticket disappeared from ledger.";
395  return tefBAD_LEDGER;
396  }
397 
398  std::uint64_t const page{(*sleTicket)[sfOwnerNode]};
399  if (!view.dirRemove(keylet::ownerDir(account), page, ticketIndex, true))
400  {
401  JLOG(j.fatal()) << "Unable to delete Ticket from owner.";
402  return tefBAD_LEDGER;
403  }
404 
405  // Update the account root's TicketCount. If the ticket count drops to
406  // zero remove the (optional) field.
407  auto sleAccount = view.peek(keylet::account(account));
408  if (!sleAccount)
409  {
410  JLOG(j.fatal()) << "Could not find Ticket owner account root.";
411  return tefBAD_LEDGER;
412  }
413 
414  if (auto ticketCount = (*sleAccount)[~sfTicketCount])
415  {
416  if (*ticketCount == 1)
417  sleAccount->makeFieldAbsent(sfTicketCount);
418  else
419  ticketCount = *ticketCount - 1;
420  }
421  else
422  {
423  JLOG(j.fatal()) << "TicketCount field missing from account root.";
424  return tefBAD_LEDGER;
425  }
426 
427  // Update the Ticket owner's reserve.
428  adjustOwnerCount(view, sleAccount, -1, j);
429 
430  // Remove Ticket from ledger.
431  view.erase(sleTicket);
432  return tesSUCCESS;
433 }
434 
435 // check stuff before you bother to lock the ledger
436 void
438 {
439  assert(account_ != beast::zero);
440 }
441 
442 TER
444 {
445  preCompute();
446 
447  // If the transactor requires a valid account and the transaction doesn't
448  // list one, preflight will have already a flagged a failure.
449  auto const sle = view().peek(keylet::account(account_));
450 
451  // sle must exist except for transactions
452  // that allow zero account.
453  assert(sle != nullptr || account_ == beast::zero);
454 
455  if (sle)
456  {
457  mPriorBalance = STAmount{(*sle)[sfBalance]}.xrp();
459 
460  TER result = consumeSeqProxy(sle);
461  if (result != tesSUCCESS)
462  return result;
463 
464  result = payFee();
465  if (result != tesSUCCESS)
466  return result;
467 
468  if (sle->isFieldPresent(sfAccountTxnID))
469  sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
470 
471  view().update(sle);
472  }
473 
474  return doApply();
475 }
476 
477 NotTEC
479 {
480  // If the pk is empty, then we must be multi-signing.
481  if (ctx.tx.getSigningPubKey().empty())
482  return checkMultiSign(ctx);
483 
484  return checkSingleSign(ctx);
485 }
486 
487 NotTEC
489 {
490  // Check that the value in the signing key slot is a public key.
491  auto const pkSigner = ctx.tx.getSigningPubKey();
492  if (!publicKeyType(makeSlice(pkSigner)))
493  {
494  JLOG(ctx.j.trace())
495  << "checkSingleSign: signing public key type is unknown";
496  return tefBAD_AUTH; // FIXME: should be better error!
497  }
498 
499  // Look up the account.
500  auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
501  auto const idAccount = ctx.tx.getAccountID(sfAccount);
502  auto const sleAccount = ctx.view.read(keylet::account(idAccount));
503  if (!sleAccount)
504  return terNO_ACCOUNT;
505 
506  bool const isMasterDisabled = sleAccount->isFlag(lsfDisableMaster);
507 
509  {
510  // Signed with regular key.
511  if ((*sleAccount)[~sfRegularKey] == idSigner)
512  {
513  return tesSUCCESS;
514  }
515 
516  // Signed with enabled mater key.
517  if (!isMasterDisabled && idAccount == idSigner)
518  {
519  return tesSUCCESS;
520  }
521 
522  // Signed with disabled master key.
523  if (isMasterDisabled && idAccount == idSigner)
524  {
525  return tefMASTER_DISABLED;
526  }
527 
528  // Signed with any other key.
529  return tefBAD_AUTH;
530  }
531 
532  if (idSigner == idAccount)
533  {
534  // Signing with the master key. Continue if it is not disabled.
535  if (isMasterDisabled)
536  return tefMASTER_DISABLED;
537  }
538  else if ((*sleAccount)[~sfRegularKey] == idSigner)
539  {
540  // Signing with the regular key. Continue.
541  }
542  else if (sleAccount->isFieldPresent(sfRegularKey))
543  {
544  // Signing key does not match master or regular key.
545  JLOG(ctx.j.trace())
546  << "checkSingleSign: Not authorized to use account.";
547  return tefBAD_AUTH;
548  }
549  else
550  {
551  // No regular key on account and signing key does not match master key.
552  // FIXME: Why differentiate this case from tefBAD_AUTH?
553  JLOG(ctx.j.trace())
554  << "checkSingleSign: Not authorized to use account.";
555  return tefBAD_AUTH_MASTER;
556  }
557 
558  return tesSUCCESS;
559 }
560 
561 NotTEC
563 {
564  auto const id = ctx.tx.getAccountID(sfAccount);
565  // Get mTxnAccountID's SignerList and Quorum.
566  std::shared_ptr<STLedgerEntry const> sleAccountSigners =
567  ctx.view.read(keylet::signers(id));
568  // If the signer list doesn't exist the account is not multi-signing.
569  if (!sleAccountSigners)
570  {
571  JLOG(ctx.j.trace())
572  << "applyTransaction: Invalid: Not a multi-signing account.";
573  return tefNOT_MULTI_SIGNING;
574  }
575 
576  // We have plans to support multiple SignerLists in the future. The
577  // presence and defaulted value of the SignerListID field will enable that.
578  assert(sleAccountSigners->isFieldPresent(sfSignerListID));
579  assert(sleAccountSigners->getFieldU32(sfSignerListID) == 0);
580 
581  auto accountSigners =
582  SignerEntries::deserialize(*sleAccountSigners, ctx.j, "ledger");
583  if (!accountSigners)
584  return accountSigners.error();
585 
586  // Get the array of transaction signers.
587  STArray const& txSigners(ctx.tx.getFieldArray(sfSigners));
588 
589  // Walk the accountSigners performing a variety of checks and see if
590  // the quorum is met.
591 
592  // Both the multiSigners and accountSigners are sorted by account. So
593  // matching multi-signers to account signers should be a simple
594  // linear walk. *All* signers must be valid or the transaction fails.
595  std::uint32_t weightSum = 0;
596  auto iter = accountSigners->begin();
597  for (auto const& txSigner : txSigners)
598  {
599  AccountID const txSignerAcctID = txSigner.getAccountID(sfAccount);
600 
601  // Attempt to match the SignerEntry with a Signer;
602  while (iter->account < txSignerAcctID)
603  {
604  if (++iter == accountSigners->end())
605  {
606  JLOG(ctx.j.trace())
607  << "applyTransaction: Invalid SigningAccount.Account.";
608  return tefBAD_SIGNATURE;
609  }
610  }
611  if (iter->account != txSignerAcctID)
612  {
613  // The SigningAccount is not in the SignerEntries.
614  JLOG(ctx.j.trace())
615  << "applyTransaction: Invalid SigningAccount.Account.";
616  return tefBAD_SIGNATURE;
617  }
618 
619  // We found the SigningAccount in the list of valid signers. Now we
620  // need to compute the accountID that is associated with the signer's
621  // public key.
622  auto const spk = txSigner.getFieldVL(sfSigningPubKey);
623 
624  if (!publicKeyType(makeSlice(spk)))
625  {
626  JLOG(ctx.j.trace())
627  << "checkMultiSign: signing public key type is unknown";
628  return tefBAD_SIGNATURE;
629  }
630 
631  AccountID const signingAcctIDFromPubKey =
633 
634  // Verify that the signingAcctID and the signingAcctIDFromPubKey
635  // belong together. Here is are the rules:
636  //
637  // 1. "Phantom account": an account that is not in the ledger
638  // A. If signingAcctID == signingAcctIDFromPubKey and the
639  // signingAcctID is not in the ledger then we have a phantom
640  // account.
641  // B. Phantom accounts are always allowed as multi-signers.
642  //
643  // 2. "Master Key"
644  // A. signingAcctID == signingAcctIDFromPubKey, and signingAcctID
645  // is in the ledger.
646  // B. If the signingAcctID in the ledger does not have the
647  // asfDisableMaster flag set, then the signature is allowed.
648  //
649  // 3. "Regular Key"
650  // A. signingAcctID != signingAcctIDFromPubKey, and signingAcctID
651  // is in the ledger.
652  // B. If signingAcctIDFromPubKey == signingAcctID.RegularKey (from
653  // ledger) then the signature is allowed.
654  //
655  // No other signatures are allowed. (January 2015)
656 
657  // In any of these cases we need to know whether the account is in
658  // the ledger. Determine that now.
659  auto sleTxSignerRoot = ctx.view.read(keylet::account(txSignerAcctID));
660 
661  if (signingAcctIDFromPubKey == txSignerAcctID)
662  {
663  // Either Phantom or Master. Phantoms automatically pass.
664  if (sleTxSignerRoot)
665  {
666  // Master Key. Account may not have asfDisableMaster set.
667  std::uint32_t const signerAccountFlags =
668  sleTxSignerRoot->getFieldU32(sfFlags);
669 
670  if (signerAccountFlags & lsfDisableMaster)
671  {
672  JLOG(ctx.j.trace())
673  << "applyTransaction: Signer:Account lsfDisableMaster.";
674  return tefMASTER_DISABLED;
675  }
676  }
677  }
678  else
679  {
680  // May be a Regular Key. Let's find out.
681  // Public key must hash to the account's regular key.
682  if (!sleTxSignerRoot)
683  {
684  JLOG(ctx.j.trace()) << "applyTransaction: Non-phantom signer "
685  "lacks account root.";
686  return tefBAD_SIGNATURE;
687  }
688 
689  if (!sleTxSignerRoot->isFieldPresent(sfRegularKey))
690  {
691  JLOG(ctx.j.trace())
692  << "applyTransaction: Account lacks RegularKey.";
693  return tefBAD_SIGNATURE;
694  }
695  if (signingAcctIDFromPubKey !=
696  sleTxSignerRoot->getAccountID(sfRegularKey))
697  {
698  JLOG(ctx.j.trace())
699  << "applyTransaction: Account doesn't match RegularKey.";
700  return tefBAD_SIGNATURE;
701  }
702  }
703  // The signer is legitimate. Add their weight toward the quorum.
704  weightSum += iter->weight;
705  }
706 
707  // Cannot perform transaction if quorum is not met.
708  if (weightSum < sleAccountSigners->getFieldU32(sfSignerQuorum))
709  {
710  JLOG(ctx.j.trace())
711  << "applyTransaction: Signers failed to meet quorum.";
712  return tefBAD_QUORUM;
713  }
714 
715  // Met the quorum. Continue.
716  return tesSUCCESS;
717 }
718 
719 //------------------------------------------------------------------------------
720 
721 static void
723  ApplyView& view,
724  std::vector<uint256> const& offers,
725  beast::Journal viewJ)
726 {
727  int removed = 0;
728 
729  for (auto const& index : offers)
730  {
731  if (auto const sleOffer = view.peek(keylet::offer(index)))
732  {
733  // offer is unfunded
734  offerDelete(view, sleOffer, viewJ);
735  if (++removed == unfundedOfferRemoveLimit)
736  return;
737  }
738  }
739 }
740 
741 static void
743  ApplyView& view,
744  std::vector<uint256> const& offers,
745  beast::Journal viewJ)
746 {
747  std::size_t removed = 0;
748 
749  for (auto const& index : offers)
750  {
751  if (auto const offer = view.peek(keylet::nftoffer(index)))
752  {
753  nft::deleteTokenOffer(view, offer);
754  if (++removed == expiredOfferRemoveLimit)
755  return;
756  }
757  }
758 }
759 
760 static void
762  ApplyView& view,
763  std::vector<uint256> const& trustLines,
764  beast::Journal viewJ)
765 {
766  if (trustLines.size() > maxDeletableAMMTrustLines)
767  {
768  JLOG(viewJ.error())
769  << "removeDeletedTrustLines: deleted trustlines exceed max "
770  << trustLines.size();
771  return;
772  }
773 
774  for (auto const& index : trustLines)
775  {
776  if (auto const sleState = view.peek({ltRIPPLE_STATE, index});
777  deleteAMMTrustLine(view, sleState, std::nullopt, viewJ) !=
778  tesSUCCESS)
779  {
780  JLOG(viewJ.error())
781  << "removeDeletedTrustLines: failed to delete AMM trustline";
782  }
783  }
784 }
785 
789 {
790  ctx_.discard();
791 
792  auto const txnAcct =
794  if (!txnAcct)
795  // The account should never be missing from the ledger. But if it
796  // is missing then we can't very well charge it a fee, can we?
797  return {tefINTERNAL, beast::zero};
798 
799  auto const balance = txnAcct->getFieldAmount(sfBalance).xrp();
800 
801  // balance should have already been checked in checkFee / preFlight.
802  assert(balance != beast::zero && (!view().open() || balance >= fee));
803 
804  // We retry/reject the transaction if the account balance is zero or we're
805  // applying against an open ledger and the balance is less than the fee
806  if (fee > balance)
807  fee = balance;
808 
809  // Since we reset the context, we need to charge the fee and update
810  // the account's sequence number (or consume the Ticket) again.
811  //
812  // If for some reason we are unable to consume the ticket or sequence
813  // then the ledger is corrupted. Rather than make things worse we
814  // reject the transaction.
815  txnAcct->setFieldAmount(sfBalance, balance - fee);
816  TER const ter{consumeSeqProxy(txnAcct)};
817  assert(isTesSuccess(ter));
818 
819  if (isTesSuccess(ter))
820  view().update(txnAcct);
821 
822  return {ter, fee};
823 }
824 
825 //------------------------------------------------------------------------------
828 {
829  JLOG(j_.trace()) << "apply: " << ctx_.tx.getTransactionID();
830 
832  NumberSO stNumberSO{view().rules().enabled(fixUniversalNumber)};
833 
834 #ifdef DEBUG
835  {
836  Serializer ser;
837  ctx_.tx.add(ser);
838  SerialIter sit(ser.slice());
839  STTx s2(sit);
840 
841  if (!s2.isEquivalent(ctx_.tx))
842  {
843  JLOG(j_.fatal()) << "Transaction serdes mismatch";
845  JLOG(j_.fatal()) << s2.getJson(JsonOptions::none);
846  assert(false);
847  }
848  }
849 #endif
850 
851  auto result = ctx_.preclaimResult;
852  if (result == tesSUCCESS)
853  result = apply();
854 
855  // No transaction can return temUNKNOWN from apply,
856  // and it can't be passed in from a preclaim.
857  assert(result != temUNKNOWN);
858 
859  if (auto stream = j_.trace())
860  stream << "preclaim result: " << transToken(result);
861 
862  bool applied = isTesSuccess(result);
863  auto fee = ctx_.tx.getFieldAmount(sfFee).xrp();
864 
865  if (ctx_.size() > oversizeMetaDataCap)
866  result = tecOVERSIZE;
867 
868  if (isTecClaim(result) && (view().flags() & tapFAIL_HARD))
869  {
870  // If the tapFAIL_HARD flag is set, a tec result
871  // must not do anything
872 
873  ctx_.discard();
874  applied = false;
875  }
876  else if (
877  (result == tecOVERSIZE) || (result == tecKILLED) ||
878  (result == tecINCOMPLETE) || (result == tecEXPIRED) ||
879  (isTecClaimHardFail(result, view().flags())))
880  {
881  JLOG(j_.trace()) << "reapplying because of " << transToken(result);
882 
883  // FIXME: This mechanism for doing work while returning a `tec` is
884  // awkward and very limiting. A more general purpose approach
885  // should be used, making it possible to do more useful work
886  // when transactions fail with a `tec` code.
887  std::vector<uint256> removedOffers;
888  std::vector<uint256> removedTrustLines;
889  std::vector<uint256> expiredNFTokenOffers;
890 
891  bool const doOffers =
892  ((result == tecOVERSIZE) || (result == tecKILLED));
893  bool const doLines = (result == tecINCOMPLETE);
894  bool const doNFTokenOffers = (result == tecEXPIRED);
895  if (doOffers || doLines || doNFTokenOffers)
896  {
897  ctx_.visit([&doOffers,
898  &removedOffers,
899  &doLines,
900  &removedTrustLines,
901  &doNFTokenOffers,
902  &expiredNFTokenOffers](
903  uint256 const& index,
904  bool isDelete,
905  std::shared_ptr<SLE const> const& before,
907  if (isDelete)
908  {
909  assert(before && after);
910  if (doOffers && before && after &&
911  (before->getType() == ltOFFER) &&
912  (before->getFieldAmount(sfTakerPays) ==
913  after->getFieldAmount(sfTakerPays)))
914  {
915  // Removal of offer found or made unfunded
916  removedOffers.push_back(index);
917  }
918 
919  if (doLines && before && after &&
920  (before->getType() == ltRIPPLE_STATE))
921  {
922  // Removal of obsolete AMM trust line
923  removedTrustLines.push_back(index);
924  }
925 
926  if (doNFTokenOffers && before && after &&
927  (before->getType() == ltNFTOKEN_OFFER))
928  expiredNFTokenOffers.push_back(index);
929  }
930  });
931  }
932 
933  // Reset the context, potentially adjusting the fee.
934  {
935  auto const resetResult = reset(fee);
936  if (!isTesSuccess(resetResult.first))
937  result = resetResult.first;
938 
939  fee = resetResult.second;
940  }
941 
942  // If necessary, remove any offers found unfunded during processing
943  if ((result == tecOVERSIZE) || (result == tecKILLED))
945  view(), removedOffers, ctx_.app.journal("View"));
946 
947  if (result == tecEXPIRED)
949  view(), expiredNFTokenOffers, ctx_.app.journal("View"));
950 
951  if (result == tecINCOMPLETE)
953  view(), removedTrustLines, ctx_.app.journal("View"));
954 
955  applied = isTecClaim(result);
956  }
957 
958  if (applied)
959  {
960  // Check invariants: if `tecINVARIANT_FAILED` is not returned, we can
961  // proceed to apply the tx
962  result = ctx_.checkInvariants(result, fee);
963 
964  if (result == tecINVARIANT_FAILED)
965  {
966  // if invariants checking failed again, reset the context and
967  // attempt to only claim a fee.
968  auto const resetResult = reset(fee);
969  if (!isTesSuccess(resetResult.first))
970  result = resetResult.first;
971 
972  fee = resetResult.second;
973 
974  // Check invariants again to ensure the fee claiming doesn't
975  // violate invariants.
976  if (isTesSuccess(result) || isTecClaim(result))
977  result = ctx_.checkInvariants(result, fee);
978  }
979 
980  // We ran through the invariant checker, which can, in some cases,
981  // return a tef error code. Don't apply the transaction in that case.
982  if (!isTecClaim(result) && !isTesSuccess(result))
983  applied = false;
984  }
985 
986  if (applied)
987  {
988  // Transaction succeeded fully or (retries are not allowed and the
989  // transaction could claim a fee)
990 
991  // The transactor and invariant checkers guarantee that this will
992  // *never* trigger but if it, somehow, happens, don't allow a tx
993  // that charges a negative fee.
994  if (fee < beast::zero)
995  Throw<std::logic_error>("fee charged is negative!");
996 
997  // Charge whatever fee they specified. The fee has already been
998  // deducted from the balance of the account that issued the
999  // transaction. We just need to account for it in the ledger
1000  // header.
1001  if (!view().open() && fee != beast::zero)
1002  ctx_.destroyXRP(fee);
1003 
1004  // Once we call apply, we will no longer be able to look at view()
1005  ctx_.apply(result);
1006  }
1007 
1008  JLOG(j_.trace()) << (applied ? "applied" : "not applied")
1009  << transToken(result);
1010 
1011  return {result, applied};
1012 }
1013 
1014 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::STArray::size
size_type size() const
Definition: STArray.h:248
ripple::Transactor::checkPriorTxAndLastLedger
static NotTEC checkPriorTxAndLastLedger(PreclaimContext const &ctx)
Definition: Transactor.cpp:335
ripple::sfSignerListID
const SF_UINT32 sfSignerListID
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:304
ripple::tefNO_TICKET
@ tefNO_TICKET
Definition: TER.h:169
ripple::Application
Definition: Application.h:116
ripple::terPRE_TICKET
@ terPRE_TICKET
Definition: TER.h:209
ripple::STObject::getFieldArray
const STArray & getFieldArray(SField const &field) const
Definition: STObject.cpp:624
ripple::STAmountSO
RAII class to set and restore the STAmount canonicalize switchover.
Definition: STAmount.h:566
ripple::preflight2
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:130
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:241
ripple::Transactor::minimumFee
static XRPAmount minimumFee(Application &app, XRPAmount baseFee, Fees const &fees, ApplyFlags flags)
Compute the minimum fee required to process a transaction with a given baseFee based on the current s...
Definition: Transactor.cpp:180
ripple::Transactor::checkMultiSign
static NotTEC checkMultiSign(PreclaimContext const &ctx)
Definition: Transactor.cpp:562
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:157
ripple::tecINVARIANT_FAILED
@ tecINVARIANT_FAILED
Definition: TER.h:284
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr< STLedgerEntry >
ripple::ApplyContext::checkInvariants
TER checkInvariants(TER const result, XRPAmount const fee)
Applies all invariant checkers one by one.
Definition: ApplyContext.cpp:147
ripple::PreclaimContext::view
ReadView const & view
Definition: Transactor.h:56
ripple::sfSigners
const SField sfSigners
ripple::isLegalAmount
bool isLegalAmount(XRPAmount const &amount)
Returns true if the amount does not exceed the initial XRP in existence.
Definition: SystemParameters.h:47
ripple::PreclaimContext::app
Application & app
Definition: Transactor.h:55
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::terINSUF_FEE_B
@ terINSUF_FEE_B
Definition: TER.h:199
ripple::PreclaimContext::j
const beast::Journal j
Definition: Transactor.h:60
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::ApplyView::peek
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:235
ripple::SignerEntries::deserialize
static Expected< std::vector< SignerEntry >, NotTEC > deserialize(STObject const &obj, beast::Journal journal, std::string const &annotation)
Definition: SignerEntries.cpp:30
ripple::Transactor::j_
const beast::Journal j_
Definition: Transactor.h:89
ripple::Transactor::checkSingleSign
static NotTEC checkSingleSign(PreclaimContext const &ctx)
Definition: Transactor.cpp:488
ripple::isTesSuccess
bool isTesSuccess(TER x)
Definition: TER.h:609
ripple::ApplyContext::preclaimResult
const TER preclaimResult
Definition: ApplyContext.h:49
std::pair
ripple::sfSequence
const SF_UINT32 sfSequence
ripple::sfRegularKey
const SF_ACCOUNT sfRegularKey
ripple::Transactor::operator()
std::pair< TER, bool > operator()()
Process the transaction.
Definition: Transactor.cpp:827
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::NumberSO
RAII class to set and restore the Number switchover.
Definition: IOUAmount.h:201
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::fixSTAmountCanonicalize
const uint256 fixSTAmountCanonicalize
ripple::expiredOfferRemoveLimit
constexpr std::size_t expiredOfferRemoveLimit
The maximum number of expired offers to delete at once.
Definition: Protocol.h:49
ripple::ApplyFlags
ApplyFlags
Definition: ApplyView.h:29
ripple::keylet::nftoffer
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:356
ripple::keylet::offer
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
Definition: Indexes.cpp:223
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::Transactor::checkSeqProxy
static NotTEC checkSeqProxy(ReadView const &view, STTx const &tx, beast::Journal j)
Definition: Transactor.cpp:263
ripple::SeqProxy::sequence
static constexpr SeqProxy sequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition: SeqProxy.h:76
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::transToken
std::string transToken(TER code)
Definition: TER.cpp:221
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::maxDeletableAMMTrustLines
constexpr std::uint16_t maxDeletableAMMTrustLines
The maximum number of trustlines to delete as part of AMM account deletion cleanup.
Definition: Protocol.h:101
ripple::telNETWORK_ID_MAKES_TX_NON_CANONICAL
@ telNETWORK_ID_MAKES_TX_NON_CANONICAL
Definition: TER.h:66
ripple::deleteAMMTrustLine
TER deleteAMMTrustLine(ApplyView &view, std::shared_ptr< SLE > sleState, std::optional< AccountID > const &ammAccountID, beast::Journal j)
Delete trustline to AMM.
Definition: View.cpp:1607
ripple::STTx::getSeqProxy
SeqProxy getSeqProxy() const
Definition: STTx.cpp:183
ripple::sfTicketSequence
const SF_UINT32 sfTicketSequence
ripple::keylet::ticket
static const ticket_t ticket
Definition: Indexes.h:167
ripple::ReadView::txExists
virtual bool txExists(key_type const &key) const =0
Returns true if a tx exists in the tx map.
ripple::PreflightContext::j
const beast::Journal j
Definition: Transactor.h:38
ripple::tecINCOMPLETE
@ tecINCOMPLETE
Definition: TER.h:306
ripple::unfundedOfferRemoveLimit
constexpr std::size_t unfundedOfferRemoveLimit
The maximum number of unfunded offers to delete at once.
Definition: Protocol.h:46
ripple::isTecClaim
bool isTecClaim(TER x)
Definition: TER.h:615
ripple::Transactor::ticketDelete
static TER ticketDelete(ApplyView &view, AccountID const &account, uint256 const &ticketIndex, beast::Journal j)
Definition: Transactor.cpp:383
ripple::tefBAD_AUTH
@ tefBAD_AUTH
Definition: TER.h:153
ripple::isTecClaimHardFail
bool isTecClaimHardFail(TER ter, ApplyFlags flags)
Return true if the transaction can claim a fee (tec), and the ApplyFlags do not allow soft failures.
Definition: applySteps.h:36
ripple::getTicketIndex
uint256 getTicketIndex(AccountID const &account, std::uint32_t ticketSeq)
Definition: Indexes.cpp:116
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:334
ripple::preflight1
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:78
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
ripple::tecKILLED
@ tecKILLED
Definition: TER.h:287
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::ApplyContext::app
Application & app
Definition: ApplyContext.h:47
ripple::SeqProxy::isTicket
constexpr bool isTicket() const
Definition: SeqProxy.h:94
ripple::sfSignerQuorum
const SF_UINT32 sfSignerQuorum
ripple::Transactor::doApply
virtual TER doApply()=0
std::vector::push_back
T push_back(T... args)
ripple::STObject::isEquivalent
bool isEquivalent(const STBase &t) const override
Definition: STObject.cpp:304
ripple::SeqProxy::isSeq
constexpr bool isSeq() const
Definition: SeqProxy.h:88
ripple::ApplyView::dirRemove
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
Definition: ApplyView.cpp:189
ripple::tefBAD_QUORUM
@ tefBAD_QUORUM
Definition: TER.h:164
ripple::publicKeyType
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
ripple::tecOVERSIZE
@ tecOVERSIZE
Definition: TER.h:282
ripple::base_uint< 160, detail::AccountIDTag >
ripple::sfTakerPays
const SF_AMOUNT sfTakerPays
ripple::preflight0
NotTEC preflight0(PreflightContext const &ctx)
Performs early sanity checks on the txid.
Definition: Transactor.cpp:41
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:154
ripple::adjustOwnerCount
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition: View.cpp:730
ripple::ltOFFER
@ ltOFFER
A ledger object which describes an offer on the DEX.
Definition: LedgerFormats.h:92
ripple::Transactor::calculateBaseFee
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Definition: Transactor.cpp:162
ripple::Transactor::checkSign
static NotTEC checkSign(PreclaimContext const &ctx)
Definition: Transactor.cpp:478
ripple::Fees
Reflects the fee settings for a particular ledger.
Definition: protocol/Fees.h:32
ripple::checkValidity
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Definition: apply.cpp:37
ripple::tefMAX_LEDGER
@ tefMAX_LEDGER
Definition: TER.h:162
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:134
ripple::removeDeletedTrustLines
static void removeDeletedTrustLines(ApplyView &view, std::vector< uint256 > const &trustLines, beast::Journal viewJ)
Definition: Transactor.cpp:761
ripple::tefMASTER_DISABLED
@ tefMASTER_DISABLED
Definition: TER.h:161
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:910
ripple::Transactor::payFee
TER payFee()
Definition: Transactor.cpp:243
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:589
ripple::ApplyContext::destroyXRP
void destroyXRP(XRPAmount const &fee)
Definition: ApplyContext.h:99
ripple::JsonOptions::none
@ none
ripple::Transactor::apply
TER apply()
Definition: Transactor.cpp:443
ripple::Application::config
virtual Config & config()=0
ripple::ltNFTOKEN_OFFER
@ ltNFTOKEN_OFFER
A ledger object which identifies an offer to buy or sell an NFT.
Definition: LedgerFormats.h:162
ripple::TERSubset< CanCvtToTER >
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::STArray
Definition: STArray.h:28
ripple::temBAD_SRC_ACCOUNT
@ temBAD_SRC_ACCOUNT
Definition: TER.h:104
ripple::telINSUF_FEE_P
@ telINSUF_FEE_P
Definition: TER.h:56
ripple::sfTicketCount
const SF_UINT32 sfTicketCount
ripple::sfAccountTxnID
const SF_UINT256 sfAccountTxnID
ripple::telREQUIRES_NETWORK_ID
@ telREQUIRES_NETWORK_ID
Definition: TER.h:65
ripple::STAmount
Definition: STAmount.h:45
ripple::PreflightContext::app
Application & app
Definition: Transactor.h:34
ripple::ApplyContext::discard
void discard()
Discard changes and start fresh.
Definition: ApplyContext.cpp:51
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::ReadView::exists
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
ripple::fixMasterKeyAsRegularKey
const uint256 fixMasterKeyAsRegularKey
ripple::STTx
Definition: STTx.h:45
ripple::SerialIter
Definition: Serializer.h:311
ripple::tecINSUFF_FEE
@ tecINSUFF_FEE
Definition: TER.h:273
ripple::ApplyContext
State information when applying a tx.
Definition: ApplyContext.h:35
ripple::STTx::getSigningPubKey
Blob getSigningPubKey() const
Definition: STTx.h:185
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint64_t
ripple::temBAD_SIGNATURE
@ temBAD_SIGNATURE
Definition: TER.h:103
ripple::temUNKNOWN
@ temUNKNOWN
Definition: TER.h:122
ripple::Transactor::consumeSeqProxy
TER consumeSeqProxy(SLE::pointer const &sleAccount)
Definition: Transactor.cpp:365
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:90
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::STTx::getJson
Json::Value getJson(JsonOptions options) const override
Definition: STTx.cpp:229
ripple::Transactor::Transactor
Transactor(Transactor const &)=delete
ripple::PreclaimContext::tx
STTx const & tx
Definition: Transactor.h:58
ripple::ApplyContext::apply
void apply(TER)
Apply the transaction result to the base.
Definition: ApplyContext.cpp:57
ripple::ApplyContext::visit
void visit(std::function< void(uint256 const &key, bool isDelete, std::shared_ptr< SLE const > const &before, std::shared_ptr< SLE const > const &after)> const &func)
Visit unapplied changes.
Definition: ApplyContext.cpp:69
ripple::STTx::getTransactionID
uint256 getTransactionID() const
Definition: STTx.h:191
ripple::terNO_ACCOUNT
@ terNO_ACCOUNT
Definition: TER.h:200
ripple::PreflightContext::PreflightContext
PreflightContext(Application &app_, STTx const &tx_, Rules const &rules_, ApplyFlags flags_, beast::Journal j_)
Definition: Transactor.cpp:144
ripple::PreclaimContext
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:52
ripple::Serializer
Definition: Serializer.h:40
ripple::STObject::add
void add(Serializer &s) const override
Definition: STObject.cpp:85
ripple::tefNOT_MULTI_SIGNING
@ tefNOT_MULTI_SIGNING
Definition: TER.h:165
ripple::SeqProxy::value
constexpr std::uint32_t value() const
Definition: SeqProxy.h:82
ripple::Transactor::reset
std::pair< TER, XRPAmount > reset(XRPAmount fee)
Reset the context, discarding any changes made and adjust the fee.
Definition: Transactor.cpp:788
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:54
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::Config::NETWORK_ID
uint32_t NETWORK_ID
Definition: Config.h:161
ripple::tapUNLIMITED
@ tapUNLIMITED
Definition: ApplyView.h:41
ripple::oversizeMetaDataCap
constexpr std::size_t oversizeMetaDataCap
The maximum number of metadata entries allowed in one transaction.
Definition: Protocol.h:52
ripple::tefPAST_SEQ
@ tefPAST_SEQ
Definition: TER.h:159
ripple::Transactor::view
ApplyView & view()
Definition: Transactor.h:107
ripple::temSEQ_AND_TICKET
@ temSEQ_AND_TICKET
Definition: TER.h:124
ripple::tecEXPIRED
@ tecEXPIRED
Definition: TER.h:285
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:122
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::tefALREADY
@ tefALREADY
Definition: TER.h:151
ripple::STObject::isFieldPresent
bool isFieldPresent(SField const &field) const
Definition: STObject.cpp:428
ripple::fixUniversalNumber
const uint256 fixUniversalNumber
ripple::Transactor::mPriorBalance
XRPAmount mPriorBalance
Definition: Transactor.h:92
ripple::Transactor::mSourceBalance
XRPAmount mSourceBalance
Definition: Transactor.h:93
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::SeqProxy
A type that represents either a sequence value or a ticket value.
Definition: SeqProxy.h:55
ripple::PreclaimContext::flags
ApplyFlags flags
Definition: Transactor.h:59
ripple::tefWRONG_PRIOR
@ tefWRONG_PRIOR
Definition: TER.h:160
ripple::tapFAIL_HARD
@ tapFAIL_HARD
Definition: ApplyView.h:34
std::vector::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
ripple::featureTicketBatch
const uint256 featureTicketBatch
ripple::terPRE_SEQ
@ terPRE_SEQ
Definition: TER.h:204
ripple::Transactor::ctx_
ApplyContext & ctx_
Definition: Transactor.h:88
std::optional< uint32_t >
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
ripple::after
static bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition: Escrow.cpp:88
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::scaleFeeLoad
XRPAmount scaleFeeLoad(XRPAmount fee, LoadFeeTrack const &feeTrack, Fees const &fees, bool bUnlimited)
Definition: LoadFeeTrack.cpp:89
ripple::sfFee
const SF_AMOUNT sfFee
ripple::Transactor::checkFee
static TER checkFee(PreclaimContext const &ctx, XRPAmount baseFee)
Definition: Transactor.cpp:190
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::tefBAD_AUTH_MASTER
@ tefBAD_AUTH_MASTER
Definition: TER.h:166
ripple::removeExpiredNFTokenOffers
static void removeExpiredNFTokenOffers(ApplyView &view, std::vector< uint256 > const &offers, beast::Journal viewJ)
Definition: Transactor.cpp:742
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:85
ripple::telWRONG_NETWORK
@ telWRONG_NETWORK
Definition: TER.h:64
ripple::sfNetworkID
const SF_UINT32 sfNetworkID
ripple::PreflightContext::tx
STTx const & tx
Definition: Transactor.h:35
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:559
ripple::PreflightContext
State information when preflighting a tx.
Definition: Transactor.h:31
ripple::Validity::SigBad
@ SigBad
Signature is bad. Didn't do local checks.
ripple::sfLastLedgerSequence
const SF_UINT32 sfLastLedgerSequence
ripple::keylet::signers
static Keylet signers(AccountID const &account, std::uint32_t page) noexcept
Definition: Indexes.cpp:269
ripple::PreflightContext::rules
const Rules rules
Definition: Transactor.h:36
ripple::ApplyContext::size
std::size_t size()
Get the number of unapplied changes.
Definition: ApplyContext.cpp:63
ripple::removeUnfundedOffers
static void removeUnfundedOffers(ApplyView &view, std::vector< uint256 > const &offers, beast::Journal viewJ)
Definition: Transactor.cpp:722
ripple::ReadView::open
virtual bool open() const =0
Returns true if this reflects an open ledger.
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:226
ripple::Transactor::account_
const AccountID account_
Definition: Transactor.h:91
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::Transactor::preCompute
virtual void preCompute()
Definition: Transactor.cpp:437
ripple::STObject::getFieldAmount
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:603
ripple::ApplyContext::tx
STTx const & tx
Definition: ApplyContext.h:48
ripple::nft::deleteTokenOffer
bool deleteTokenOffer(ApplyView &view, std::shared_ptr< SLE > const &offer)
Deletes the given token offer.
Definition: NFTokenUtils.cpp:605
ripple::temINVALID
@ temINVALID
Definition: TER.h:108
ripple::Fees::base
XRPAmount base
Definition: protocol/Fees.h:34
ripple::open
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.
Definition: SociDB.cpp:98
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::tefBAD_SIGNATURE
@ tefBAD_SIGNATURE
Definition: TER.h:163
ripple::NotTEC
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:540
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:583