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