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