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