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