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