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