rippled
View.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/basics/Log.h>
21 #include <ripple/basics/StringUtilities.h>
22 #include <ripple/basics/chrono.h>
23 #include <ripple/basics/contract.h>
24 #include <ripple/ledger/BookDirs.h>
25 #include <ripple/ledger/ReadView.h>
26 #include <ripple/ledger/View.h>
27 #include <ripple/protocol/Feature.h>
28 #include <ripple/protocol/Protocol.h>
29 #include <ripple/protocol/Quality.h>
30 #include <ripple/protocol/st.h>
31 #include <boost/algorithm/string.hpp>
32 #include <cassert>
33 #include <optional>
34 
35 namespace ripple {
36 
37 namespace detail {
38 
39 template <
40  class V,
41  class N,
42  class = std::enable_if_t<
43  std::is_same_v<std::remove_cv_t<N>, SLE> &&
44  std::is_base_of_v<ReadView, V>>>
45 bool
47  V& view,
48  uint256 const& root,
49  std::shared_ptr<N>& page,
50  unsigned int& index,
51  uint256& entry)
52 {
53  auto const& svIndexes = page->getFieldV256(sfIndexes);
54  assert(index <= svIndexes.size());
55 
56  if (index >= svIndexes.size())
57  {
58  auto const next = page->getFieldU64(sfIndexNext);
59 
60  if (!next)
61  {
62  entry.zero();
63  return false;
64  }
65 
66  if constexpr (std::is_const_v<N>)
67  page = view.read(keylet::page(root, next));
68  else
69  page = view.peek(keylet::page(root, next));
70 
71  assert(page);
72 
73  if (!page)
74  return false;
75 
76  index = 0;
77 
78  return internalDirNext(view, root, page, index, entry);
79  }
80 
81  entry = svIndexes[index++];
82  return true;
83 }
84 
85 template <
86  class V,
87  class N,
88  class = std::enable_if_t<
89  std::is_same_v<std::remove_cv_t<N>, SLE> &&
90  std::is_base_of_v<ReadView, V>>>
91 bool
93  V& view,
94  uint256 const& root,
95  std::shared_ptr<N>& page,
96  unsigned int& index,
97  uint256& entry)
98 {
99  if constexpr (std::is_const_v<N>)
100  page = view.read(keylet::page(root));
101  else
102  page = view.peek(keylet::page(root));
103 
104  assert(page);
105 
106  index = 0;
107 
108  return internalDirNext(view, root, page, index, entry);
109 }
110 
111 } // namespace detail
112 
113 bool
115  ApplyView& view,
116  uint256 const& root,
117  std::shared_ptr<SLE>& page,
118  unsigned int& index,
119  uint256& entry)
120 {
121  return detail::internalDirFirst(view, root, page, index, entry);
122 }
123 
124 bool
126  ApplyView& view,
127  uint256 const& root,
128  std::shared_ptr<SLE>& page,
129  unsigned int& index,
130  uint256& entry)
131 {
132  return detail::internalDirNext(view, root, page, index, entry);
133 }
134 
135 bool
137  ReadView const& view,
138  uint256 const& root,
140  unsigned int& index,
141  uint256& entry)
142 {
143  return detail::internalDirFirst(view, root, page, index, entry);
144 }
145 
146 bool
148  ReadView const& view,
149  uint256 const& root,
151  unsigned int& index,
152  uint256& entry)
153 {
154  return detail::internalDirNext(view, root, page, index, entry);
155 }
156 
157 //------------------------------------------------------------------------------
158 //
159 // Observers
160 //
161 //------------------------------------------------------------------------------
162 
163 void
164 addRaw(LedgerInfo const& info, Serializer& s, bool includeHash)
165 {
166  s.add32(info.seq);
167  s.add64(info.drops.drops());
168  s.addBitString(info.parentHash);
169  s.addBitString(info.txHash);
170  s.addBitString(info.accountHash);
171  s.add32(info.parentCloseTime.time_since_epoch().count());
172  s.add32(info.closeTime.time_since_epoch().count());
173  s.add8(info.closeTimeResolution.count());
174  s.add8(info.closeFlags);
175 
176  if (includeHash)
177  s.addBitString(info.hash);
178 }
179 
180 bool
181 isGlobalFrozen(ReadView const& view, AccountID const& issuer)
182 {
183  if (isXRP(issuer))
184  return false;
185  if (auto const sle = view.read(keylet::account(issuer)))
186  return sle->isFlag(lsfGlobalFreeze);
187  return false;
188 }
189 
190 // Can the specified account spend the specified currency issued by
191 // the specified issuer or does the freeze flag prohibit it?
192 bool
194  ReadView const& view,
195  AccountID const& account,
196  Currency const& currency,
197  AccountID const& issuer)
198 {
199  if (isXRP(currency))
200  return false;
201  auto sle = view.read(keylet::account(issuer));
202  if (sle && sle->isFlag(lsfGlobalFreeze))
203  return true;
204  if (issuer != account)
205  {
206  // Check if the issuer froze the line
207  sle = view.read(keylet::line(account, issuer, currency));
208  if (sle &&
209  sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
210  return true;
211  }
212  return false;
213 }
214 
215 STAmount
217  ReadView const& view,
218  AccountID const& account,
219  Currency const& currency,
220  AccountID const& issuer,
221  FreezeHandling zeroIfFrozen,
222  beast::Journal j)
223 {
224  STAmount amount;
225  if (isXRP(currency))
226  {
227  return {xrpLiquid(view, account, 0, j)};
228  }
229 
230  // IOU: Return balance on trust line modulo freeze
231  auto const sle = view.read(keylet::line(account, issuer, currency));
232  if (!sle)
233  {
234  amount.clear({currency, issuer});
235  }
236  else if (
237  (zeroIfFrozen == fhZERO_IF_FROZEN) &&
238  isFrozen(view, account, currency, issuer))
239  {
240  amount.clear(Issue(currency, issuer));
241  }
242  else
243  {
244  amount = sle->getFieldAmount(sfBalance);
245  if (account > issuer)
246  {
247  // Put balance in account terms.
248  amount.negate();
249  }
250  amount.setIssuer(issuer);
251  }
252  JLOG(j.trace()) << "accountHolds:"
253  << " account=" << to_string(account)
254  << " amount=" << amount.getFullText();
255 
256  return view.balanceHook(account, issuer, amount);
257 }
258 
259 STAmount
261  ReadView const& view,
262  AccountID const& id,
263  STAmount const& saDefault,
264  FreezeHandling freezeHandling,
265  beast::Journal j)
266 {
267  STAmount saFunds;
268 
269  if (!saDefault.native() && saDefault.getIssuer() == id)
270  {
271  saFunds = saDefault;
272  JLOG(j.trace()) << "accountFunds:"
273  << " account=" << to_string(id)
274  << " saDefault=" << saDefault.getFullText()
275  << " SELF-FUNDED";
276  }
277  else
278  {
279  saFunds = accountHolds(
280  view,
281  id,
282  saDefault.getCurrency(),
283  saDefault.getIssuer(),
284  freezeHandling,
285  j);
286  JLOG(j.trace()) << "accountFunds:"
287  << " account=" << to_string(id)
288  << " saDefault=" << saDefault.getFullText()
289  << " saFunds=" << saFunds.getFullText();
290  }
291  return saFunds;
292 }
293 
294 // Prevent ownerCount from wrapping under error conditions.
295 //
296 // adjustment allows the ownerCount to be adjusted up or down in multiple steps.
297 // If id != std::nullopt, then do error reporting.
298 //
299 // Returns adjusted owner count.
300 static std::uint32_t
302  std::uint32_t current,
303  std::int32_t adjustment,
304  std::optional<AccountID> const& id = std::nullopt,
306 {
307  std::uint32_t adjusted{current + adjustment};
308  if (adjustment > 0)
309  {
310  // Overflow is well defined on unsigned
311  if (adjusted < current)
312  {
313  if (id)
314  {
315  JLOG(j.fatal())
316  << "Account " << *id << " owner count exceeds max!";
317  }
319  }
320  }
321  else
322  {
323  // Underflow is well defined on unsigned
324  if (adjusted > current)
325  {
326  if (id)
327  {
328  JLOG(j.fatal())
329  << "Account " << *id << " owner count set below 0!";
330  }
331  adjusted = 0;
332  assert(!id);
333  }
334  }
335  return adjusted;
336 }
337 
338 XRPAmount
340  ReadView const& view,
341  AccountID const& id,
342  std::int32_t ownerCountAdj,
343  beast::Journal j)
344 {
345  auto const sle = view.read(keylet::account(id));
346  if (sle == nullptr)
347  return beast::zero;
348 
349  // Return balance minus reserve
350  std::uint32_t const ownerCount = confineOwnerCount(
351  view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
352 
353  auto const reserve = view.fees().accountReserve(ownerCount);
354 
355  auto const fullBalance = sle->getFieldAmount(sfBalance);
356 
357  auto const balance = view.balanceHook(id, xrpAccount(), fullBalance);
358 
359  STAmount amount = balance - reserve;
360  if (balance < reserve)
361  amount.clear();
362 
363  JLOG(j.trace()) << "accountHolds:"
364  << " account=" << to_string(id)
365  << " amount=" << amount.getFullText()
366  << " fullBalance=" << fullBalance.getFullText()
367  << " balance=" << balance.getFullText()
368  << " reserve=" << reserve << " ownerCount=" << ownerCount
369  << " ownerCountAdj=" << ownerCountAdj;
370 
371  return amount.xrp();
372 }
373 
374 void
376  ReadView const& view,
377  AccountID const& id,
379 {
380  auto const root = keylet::ownerDir(id);
381  auto pos = root;
382  for (;;)
383  {
384  auto sle = view.read(pos);
385  if (!sle)
386  return;
387  // VFALCO NOTE We aren't checking field exists?
388  for (auto const& key : sle->getFieldV256(sfIndexes))
389  f(view.read(keylet::child(key)));
390  auto const next = sle->getFieldU64(sfIndexNext);
391  if (!next)
392  return;
393  pos = keylet::page(root, next);
394  }
395 }
396 
397 bool
399  ReadView const& view,
400  AccountID const& id,
401  uint256 const& after,
402  std::uint64_t const hint,
403  unsigned int limit,
405 {
406  auto const rootIndex = keylet::ownerDir(id);
407  auto currentIndex = rootIndex;
408 
409  // If startAfter is not zero try jumping to that page using the hint
410  if (after.isNonZero())
411  {
412  auto const hintIndex = keylet::page(rootIndex, hint);
413  auto hintDir = view.read(hintIndex);
414  if (hintDir)
415  {
416  for (auto const& key : hintDir->getFieldV256(sfIndexes))
417  {
418  if (key == after)
419  {
420  // We found the hint, we can start here
421  currentIndex = hintIndex;
422  break;
423  }
424  }
425  }
426 
427  bool found = false;
428  for (;;)
429  {
430  auto const ownerDir = view.read(currentIndex);
431  if (!ownerDir)
432  return found;
433  for (auto const& key : ownerDir->getFieldV256(sfIndexes))
434  {
435  if (!found)
436  {
437  if (key == after)
438  found = true;
439  }
440  else if (f(view.read(keylet::child(key))) && limit-- <= 1)
441  {
442  return found;
443  }
444  }
445 
446  auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext);
447  if (uNodeNext == 0)
448  return found;
449  currentIndex = keylet::page(rootIndex, uNodeNext);
450  }
451  }
452  else
453  {
454  for (;;)
455  {
456  auto const ownerDir = view.read(currentIndex);
457  if (!ownerDir)
458  return true;
459  for (auto const& key : ownerDir->getFieldV256(sfIndexes))
460  if (f(view.read(keylet::child(key))) && limit-- <= 1)
461  return true;
462  auto const uNodeNext = ownerDir->getFieldU64(sfIndexNext);
463  if (uNodeNext == 0)
464  return true;
465  currentIndex = keylet::page(rootIndex, uNodeNext);
466  }
467  }
468 }
469 
470 Rate
471 transferRate(ReadView const& view, AccountID const& issuer)
472 {
473  auto const sle = view.read(keylet::account(issuer));
474 
475  if (sle && sle->isFieldPresent(sfTransferRate))
476  return Rate{sle->getFieldU32(sfTransferRate)};
477 
478  return parityRate;
479 }
480 
481 bool
483  ReadView const& validLedger,
484  ReadView const& testLedger,
486  const char* reason)
487 {
488  bool ret = true;
489 
490  if (validLedger.info().seq < testLedger.info().seq)
491  {
492  // valid -> ... -> test
493  auto hash = hashOfSeq(
494  testLedger,
495  validLedger.info().seq,
496  beast::Journal{beast::Journal::getNullSink()});
497  if (hash && (*hash != validLedger.info().hash))
498  {
499  JLOG(s) << reason << " incompatible with valid ledger";
500 
501  JLOG(s) << "Hash(VSeq): " << to_string(*hash);
502 
503  ret = false;
504  }
505  }
506  else if (validLedger.info().seq > testLedger.info().seq)
507  {
508  // test -> ... -> valid
509  auto hash = hashOfSeq(
510  validLedger,
511  testLedger.info().seq,
512  beast::Journal{beast::Journal::getNullSink()});
513  if (hash && (*hash != testLedger.info().hash))
514  {
515  JLOG(s) << reason << " incompatible preceding ledger";
516 
517  JLOG(s) << "Hash(NSeq): " << to_string(*hash);
518 
519  ret = false;
520  }
521  }
522  else if (
523  (validLedger.info().seq == testLedger.info().seq) &&
524  (validLedger.info().hash != testLedger.info().hash))
525  {
526  // Same sequence number, different hash
527  JLOG(s) << reason << " incompatible ledger";
528 
529  ret = false;
530  }
531 
532  if (!ret)
533  {
534  JLOG(s) << "Val: " << validLedger.info().seq << " "
535  << to_string(validLedger.info().hash);
536 
537  JLOG(s) << "New: " << testLedger.info().seq << " "
538  << to_string(testLedger.info().hash);
539  }
540 
541  return ret;
542 }
543 
544 bool
546  uint256 const& validHash,
547  LedgerIndex validIndex,
548  ReadView const& testLedger,
550  const char* reason)
551 {
552  bool ret = true;
553 
554  if (testLedger.info().seq > validIndex)
555  {
556  // Ledger we are testing follows last valid ledger
557  auto hash = hashOfSeq(
558  testLedger,
559  validIndex,
561  if (hash && (*hash != validHash))
562  {
563  JLOG(s) << reason << " incompatible following ledger";
564  JLOG(s) << "Hash(VSeq): " << to_string(*hash);
565 
566  ret = false;
567  }
568  }
569  else if (
570  (validIndex == testLedger.info().seq) &&
571  (testLedger.info().hash != validHash))
572  {
573  JLOG(s) << reason << " incompatible ledger";
574 
575  ret = false;
576  }
577 
578  if (!ret)
579  {
580  JLOG(s) << "Val: " << validIndex << " " << to_string(validHash);
581 
582  JLOG(s) << "New: " << testLedger.info().seq << " "
583  << to_string(testLedger.info().hash);
584  }
585 
586  return ret;
587 }
588 
589 bool
590 dirIsEmpty(ReadView const& view, Keylet const& k)
591 {
592  auto const sleNode = view.read(k);
593  if (!sleNode)
594  return true;
595  if (!sleNode->getFieldV256(sfIndexes).empty())
596  return false;
597  // The first page of a directory may legitimately be empty even if there
598  // are other pages (the first page is the anchor page) so check to see if
599  // there is another page. If there is, the directory isn't empty.
600  return sleNode->getFieldU64(sfIndexNext) == 0;
601 }
602 
605 {
606  std::set<uint256> amendments;
607 
608  if (auto const sle = view.read(keylet::amendments()))
609  {
610  if (sle->isFieldPresent(sfAmendments))
611  {
612  auto const& v = sle->getFieldV256(sfAmendments);
613  amendments.insert(v.begin(), v.end());
614  }
615  }
616 
617  return amendments;
618 }
619 
622 {
624 
625  if (auto const sle = view.read(keylet::amendments()))
626  {
627  if (sle->isFieldPresent(sfMajorities))
628  {
629  using tp = NetClock::time_point;
630  using d = tp::duration;
631 
632  auto const majorities = sle->getFieldArray(sfMajorities);
633 
634  for (auto const& m : majorities)
635  ret[m.getFieldH256(sfAmendment)] =
636  tp(d(m.getFieldU32(sfCloseTime)));
637  }
638  }
639 
640  return ret;
641 }
642 
644 hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
645 {
646  // Easy cases...
647  if (seq > ledger.seq())
648  {
649  JLOG(journal.warn())
650  << "Can't get seq " << seq << " from " << ledger.seq() << " future";
651  return std::nullopt;
652  }
653  if (seq == ledger.seq())
654  return ledger.info().hash;
655  if (seq == (ledger.seq() - 1))
656  return ledger.info().parentHash;
657 
658  if (int diff = ledger.seq() - seq; diff <= 256)
659  {
660  // Within 256...
661  auto const hashIndex = ledger.read(keylet::skip());
662  if (hashIndex)
663  {
664  assert(
665  hashIndex->getFieldU32(sfLastLedgerSequence) ==
666  (ledger.seq() - 1));
667  STVector256 vec = hashIndex->getFieldV256(sfHashes);
668  if (vec.size() >= diff)
669  return vec[vec.size() - diff];
670  JLOG(journal.warn())
671  << "Ledger " << ledger.seq() << " missing hash for " << seq
672  << " (" << vec.size() << "," << diff << ")";
673  }
674  else
675  {
676  JLOG(journal.warn())
677  << "Ledger " << ledger.seq() << ":" << ledger.info().hash
678  << " missing normal list";
679  }
680  }
681 
682  if ((seq & 0xff) != 0)
683  {
684  JLOG(journal.debug())
685  << "Can't get seq " << seq << " from " << ledger.seq() << " past";
686  return std::nullopt;
687  }
688 
689  // in skiplist
690  auto const hashIndex = ledger.read(keylet::skip(seq));
691  if (hashIndex)
692  {
693  auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence);
694  assert(lastSeq >= seq);
695  assert((lastSeq & 0xff) == 0);
696  auto const diff = (lastSeq - seq) >> 8;
697  STVector256 vec = hashIndex->getFieldV256(sfHashes);
698  if (vec.size() > diff)
699  return vec[vec.size() - diff - 1];
700  }
701  JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq()
702  << " error";
703  return std::nullopt;
704 }
705 
706 //------------------------------------------------------------------------------
707 //
708 // Modifiers
709 //
710 //------------------------------------------------------------------------------
711 
712 void
714  ApplyView& view,
715  std::shared_ptr<SLE> const& sle,
716  std::int32_t amount,
717  beast::Journal j)
718 {
719  if (!sle)
720  return;
721  assert(amount != 0);
723  AccountID const id = (*sle)[sfAccount];
724  std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
725  view.adjustOwnerCountHook(id, current, adjusted);
726  sle->setFieldU32(sfOwnerCount, adjusted);
727  view.update(sle);
728 }
729 
730 std::function<void(SLE::ref)>
732 {
733  return [&account](std::shared_ptr<SLE> const& sle) {
734  (*sle)[sfOwner] = account;
735  };
736 }
737 
738 TER
740  ApplyView& view,
741  const bool bSrcHigh,
742  AccountID const& uSrcAccountID,
743  AccountID const& uDstAccountID,
744  uint256 const& uIndex, // --> ripple state entry
745  SLE::ref sleAccount, // --> the account being set.
746  const bool bAuth, // --> authorize account.
747  const bool bNoRipple, // --> others cannot ripple through
748  const bool bFreeze, // --> funds cannot leave
749  STAmount const& saBalance, // --> balance of account being set.
750  // Issuer should be noAccount()
751  STAmount const& saLimit, // --> limit for account being set.
752  // Issuer should be the account being set.
753  std::uint32_t uQualityIn,
754  std::uint32_t uQualityOut,
755  beast::Journal j)
756 {
757  JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", "
758  << to_string(uDstAccountID) << ", "
759  << saBalance.getFullText();
760 
761  auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
762  auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
763 
764  auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
765  view.insert(sleRippleState);
766 
767  auto lowNode = view.dirInsert(
768  keylet::ownerDir(uLowAccountID),
769  sleRippleState->key(),
770  describeOwnerDir(uLowAccountID));
771 
772  if (!lowNode)
773  return tecDIR_FULL;
774 
775  auto highNode = view.dirInsert(
776  keylet::ownerDir(uHighAccountID),
777  sleRippleState->key(),
778  describeOwnerDir(uHighAccountID));
779 
780  if (!highNode)
781  return tecDIR_FULL;
782 
783  const bool bSetDst = saLimit.getIssuer() == uDstAccountID;
784  const bool bSetHigh = bSrcHigh ^ bSetDst;
785 
786  assert(sleAccount);
787  if (!sleAccount)
788  return tefINTERNAL;
789 
790  assert(
791  sleAccount->getAccountID(sfAccount) ==
792  (bSetHigh ? uHighAccountID : uLowAccountID));
793  auto const slePeer =
794  view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
795  if (!slePeer)
796  return tecNO_TARGET;
797 
798  // Remember deletion hints.
799  sleRippleState->setFieldU64(sfLowNode, *lowNode);
800  sleRippleState->setFieldU64(sfHighNode, *highNode);
801 
802  sleRippleState->setFieldAmount(
803  bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
804  sleRippleState->setFieldAmount(
805  bSetHigh ? sfLowLimit : sfHighLimit,
806  STAmount(
807  {saBalance.getCurrency(),
808  bSetDst ? uSrcAccountID : uDstAccountID}));
809 
810  if (uQualityIn)
811  sleRippleState->setFieldU32(
812  bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
813 
814  if (uQualityOut)
815  sleRippleState->setFieldU32(
816  bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
817 
818  std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
819 
820  if (bAuth)
821  {
822  uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
823  }
824  if (bNoRipple)
825  {
826  uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
827  }
828  if (bFreeze)
829  {
830  uFlags |= (!bSetHigh ? lsfLowFreeze : lsfHighFreeze);
831  }
832 
833  if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
834  {
835  // The other side's default is no rippling
836  uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
837  }
838 
839  sleRippleState->setFieldU32(sfFlags, uFlags);
840  adjustOwnerCount(view, sleAccount, 1, j);
841 
842  // ONLY: Create ripple balance.
843  sleRippleState->setFieldAmount(
844  sfBalance, bSetHigh ? -saBalance : saBalance);
845 
846  view.creditHook(
847  uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed());
848 
849  return tesSUCCESS;
850 }
851 
852 TER
854  ApplyView& view,
855  std::shared_ptr<SLE> const& sleRippleState,
856  AccountID const& uLowAccountID,
857  AccountID const& uHighAccountID,
858  beast::Journal j)
859 {
860  // Detect legacy dirs.
861  std::uint64_t uLowNode = sleRippleState->getFieldU64(sfLowNode);
862  std::uint64_t uHighNode = sleRippleState->getFieldU64(sfHighNode);
863 
864  JLOG(j.trace()) << "trustDelete: Deleting ripple line: low";
865 
866  if (!view.dirRemove(
867  keylet::ownerDir(uLowAccountID),
868  uLowNode,
869  sleRippleState->key(),
870  false))
871  {
872  return tefBAD_LEDGER;
873  }
874 
875  JLOG(j.trace()) << "trustDelete: Deleting ripple line: high";
876 
877  if (!view.dirRemove(
878  keylet::ownerDir(uHighAccountID),
879  uHighNode,
880  sleRippleState->key(),
881  false))
882  {
883  return tefBAD_LEDGER;
884  }
885 
886  JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
887  view.erase(sleRippleState);
888 
889  return tesSUCCESS;
890 }
891 
892 TER
894 {
895  if (!sle)
896  return tesSUCCESS;
897  auto offerIndex = sle->key();
898  auto owner = sle->getAccountID(sfAccount);
899 
900  // Detect legacy directories.
901  uint256 uDirectory = sle->getFieldH256(sfBookDirectory);
902 
903  if (!view.dirRemove(
904  keylet::ownerDir(owner),
905  sle->getFieldU64(sfOwnerNode),
906  offerIndex,
907  false))
908  {
909  return tefBAD_LEDGER;
910  }
911 
912  if (!view.dirRemove(
913  keylet::page(uDirectory),
914  sle->getFieldU64(sfBookNode),
915  offerIndex,
916  false))
917  {
918  return tefBAD_LEDGER;
919  }
920 
921  adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j);
922 
923  view.erase(sle);
924 
925  return tesSUCCESS;
926 }
927 
928 // Direct send w/o fees:
929 // - Redeeming IOUs and/or sending sender's own IOUs.
930 // - Create trust line if needed.
931 // --> bCheckIssuer : normally require issuer to be involved.
932 TER
934  ApplyView& view,
935  AccountID const& uSenderID,
936  AccountID const& uReceiverID,
937  STAmount const& saAmount,
938  bool bCheckIssuer,
939  beast::Journal j)
940 {
941  AccountID const& issuer = saAmount.getIssuer();
942  Currency const& currency = saAmount.getCurrency();
943 
944  // Make sure issuer is involved.
945  assert(!bCheckIssuer || uSenderID == issuer || uReceiverID == issuer);
946  (void)issuer;
947 
948  // Disallow sending to self.
949  assert(uSenderID != uReceiverID);
950 
951  bool const bSenderHigh = uSenderID > uReceiverID;
952  auto const index = keylet::line(uSenderID, uReceiverID, currency);
953 
954  assert(!isXRP(uSenderID) && uSenderID != noAccount());
955  assert(!isXRP(uReceiverID) && uReceiverID != noAccount());
956 
957  // If the line exists, modify it accordingly.
958  if (auto const sleRippleState = view.peek(index))
959  {
960  STAmount saBalance = sleRippleState->getFieldAmount(sfBalance);
961 
962  if (bSenderHigh)
963  saBalance.negate(); // Put balance in sender terms.
964 
965  view.creditHook(uSenderID, uReceiverID, saAmount, saBalance);
966 
967  STAmount const saBefore = saBalance;
968 
969  saBalance -= saAmount;
970 
971  JLOG(j.trace()) << "rippleCredit: " << to_string(uSenderID) << " -> "
972  << to_string(uReceiverID)
973  << " : before=" << saBefore.getFullText()
974  << " amount=" << saAmount.getFullText()
975  << " after=" << saBalance.getFullText();
976 
977  std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags));
978  bool bDelete = false;
979 
980  // FIXME This NEEDS to be cleaned up and simplified. It's impossible
981  // for anyone to understand.
982  if (saBefore > beast::zero
983  // Sender balance was positive.
984  && saBalance <= beast::zero
985  // Sender is zero or negative.
986  && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
987  // Sender reserve is set.
988  &&
989  static_cast<bool>(
990  uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
991  static_cast<bool>(
992  view.read(keylet::account(uSenderID))->getFlags() &
993  lsfDefaultRipple) &&
994  !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
995  !sleRippleState->getFieldAmount(
996  !bSenderHigh ? sfLowLimit : sfHighLimit)
997  // Sender trust limit is 0.
998  && !sleRippleState->getFieldU32(
999  !bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1000  // Sender quality in is 0.
1001  && !sleRippleState->getFieldU32(
1002  !bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1003  // Sender quality out is 0.
1004  {
1005  // Clear the reserve of the sender, possibly delete the line!
1007  view, view.peek(keylet::account(uSenderID)), -1, j);
1008 
1009  // Clear reserve flag.
1010  sleRippleState->setFieldU32(
1011  sfFlags,
1012  uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1013 
1014  // Balance is zero, receiver reserve is clear.
1015  bDelete = !saBalance // Balance is zero.
1016  && !(uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve));
1017  // Receiver reserve is clear.
1018  }
1019 
1020  if (bSenderHigh)
1021  saBalance.negate();
1022 
1023  // Want to reflect balance to zero even if we are deleting line.
1024  sleRippleState->setFieldAmount(sfBalance, saBalance);
1025  // ONLY: Adjust ripple balance.
1026 
1027  if (bDelete)
1028  {
1029  return trustDelete(
1030  view,
1031  sleRippleState,
1032  bSenderHigh ? uReceiverID : uSenderID,
1033  !bSenderHigh ? uReceiverID : uSenderID,
1034  j);
1035  }
1036 
1037  view.update(sleRippleState);
1038  return tesSUCCESS;
1039  }
1040 
1041  STAmount const saReceiverLimit({currency, uReceiverID});
1042  STAmount saBalance{saAmount};
1043 
1044  saBalance.setIssuer(noAccount());
1045 
1046  JLOG(j.debug()) << "rippleCredit: "
1047  "create line: "
1048  << to_string(uSenderID) << " -> " << to_string(uReceiverID)
1049  << " : " << saAmount.getFullText();
1050 
1051  auto const sleAccount = view.peek(keylet::account(uReceiverID));
1052  if (!sleAccount)
1053  return tefINTERNAL;
1054 
1055  bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
1056 
1057  return trustCreate(
1058  view,
1059  bSenderHigh,
1060  uSenderID,
1061  uReceiverID,
1062  index.key,
1063  sleAccount,
1064  false,
1065  noRipple,
1066  false,
1067  saBalance,
1068  saReceiverLimit,
1069  0,
1070  0,
1071  j);
1072 }
1073 
1074 // Send regardless of limits.
1075 // --> saAmount: Amount/currency/issuer to deliver to receiver.
1076 // <-- saActual: Amount actually cost. Sender pays fees.
1077 static TER
1079  ApplyView& view,
1080  AccountID const& uSenderID,
1081  AccountID const& uReceiverID,
1082  STAmount const& saAmount,
1083  STAmount& saActual,
1084  beast::Journal j)
1085 {
1086  auto const issuer = saAmount.getIssuer();
1087 
1088  assert(!isXRP(uSenderID) && !isXRP(uReceiverID));
1089  assert(uSenderID != uReceiverID);
1090 
1091  if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount())
1092  {
1093  // Direct send: redeeming IOUs and/or sending own IOUs.
1094  auto const ter =
1095  rippleCredit(view, uSenderID, uReceiverID, saAmount, false, j);
1096  if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS)
1097  return ter;
1098  saActual = saAmount;
1099  return tesSUCCESS;
1100  }
1101 
1102  // Sending 3rd party IOUs: transit.
1103 
1104  // Calculate the amount to transfer accounting
1105  // for any transfer fees:
1106  saActual = multiply(saAmount, transferRate(view, issuer));
1107 
1108  JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > "
1109  << to_string(uReceiverID)
1110  << " : deliver=" << saAmount.getFullText()
1111  << " cost=" << saActual.getFullText();
1112 
1113  TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j);
1114 
1115  if (tesSUCCESS == terResult)
1116  terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j);
1117 
1118  return terResult;
1119 }
1120 
1121 TER
1123  ApplyView& view,
1124  AccountID const& uSenderID,
1125  AccountID const& uReceiverID,
1126  STAmount const& saAmount,
1127  beast::Journal j)
1128 {
1129  assert(saAmount >= beast::zero);
1130 
1131  /* If we aren't sending anything or if the sender is the same as the
1132  * receiver then we don't need to do anything.
1133  */
1134  if (!saAmount || (uSenderID == uReceiverID))
1135  return tesSUCCESS;
1136 
1137  if (!saAmount.native())
1138  {
1139  STAmount saActual;
1140 
1141  JLOG(j.trace()) << "accountSend: " << to_string(uSenderID) << " -> "
1142  << to_string(uReceiverID) << " : "
1143  << saAmount.getFullText();
1144 
1145  return rippleSend(view, uSenderID, uReceiverID, saAmount, saActual, j);
1146  }
1147 
1148  /* XRP send which does not check reserve and can do pure adjustment.
1149  * Note that sender or receiver may be null and this not a mistake; this
1150  * setup is used during pathfinding and it is carefully controlled to
1151  * ensure that transfers are balanced.
1152  */
1153  TER terResult(tesSUCCESS);
1154 
1155  SLE::pointer sender = uSenderID != beast::zero
1156  ? view.peek(keylet::account(uSenderID))
1157  : SLE::pointer();
1158  SLE::pointer receiver = uReceiverID != beast::zero
1159  ? view.peek(keylet::account(uReceiverID))
1160  : SLE::pointer();
1161 
1162  if (auto stream = j.trace())
1163  {
1164  std::string sender_bal("-");
1165  std::string receiver_bal("-");
1166 
1167  if (sender)
1168  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1169 
1170  if (receiver)
1171  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1172 
1173  stream << "accountSend> " << to_string(uSenderID) << " (" << sender_bal
1174  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1175  << ") : " << saAmount.getFullText();
1176  }
1177 
1178  if (sender)
1179  {
1180  if (sender->getFieldAmount(sfBalance) < saAmount)
1181  {
1182  // VFALCO Its laborious to have to mutate the
1183  // TER based on params everywhere
1184  terResult = view.open() ? TER{telFAILED_PROCESSING}
1186  }
1187  else
1188  {
1189  auto const sndBal = sender->getFieldAmount(sfBalance);
1190  view.creditHook(uSenderID, xrpAccount(), saAmount, sndBal);
1191 
1192  // Decrement XRP balance.
1193  sender->setFieldAmount(sfBalance, sndBal - saAmount);
1194  view.update(sender);
1195  }
1196  }
1197 
1198  if (tesSUCCESS == terResult && receiver)
1199  {
1200  // Increment XRP balance.
1201  auto const rcvBal = receiver->getFieldAmount(sfBalance);
1202  receiver->setFieldAmount(sfBalance, rcvBal + saAmount);
1203  view.creditHook(xrpAccount(), uReceiverID, saAmount, -rcvBal);
1204 
1205  view.update(receiver);
1206  }
1207 
1208  if (auto stream = j.trace())
1209  {
1210  std::string sender_bal("-");
1211  std::string receiver_bal("-");
1212 
1213  if (sender)
1214  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1215 
1216  if (receiver)
1217  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1218 
1219  stream << "accountSend< " << to_string(uSenderID) << " (" << sender_bal
1220  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1221  << ") : " << saAmount.getFullText();
1222  }
1223 
1224  return terResult;
1225 }
1226 
1227 static bool
1229  ApplyView& view,
1230  SLE::pointer state,
1231  bool bSenderHigh,
1232  AccountID const& sender,
1233  STAmount const& before,
1234  STAmount const& after,
1235  beast::Journal j)
1236 {
1237  if (!state)
1238  return false;
1239  std::uint32_t const flags(state->getFieldU32(sfFlags));
1240 
1241  auto sle = view.peek(keylet::account(sender));
1242  if (!sle)
1243  return false;
1244 
1245  // YYY Could skip this if rippling in reverse.
1246  if (before > beast::zero
1247  // Sender balance was positive.
1248  && after <= beast::zero
1249  // Sender is zero or negative.
1250  && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
1251  // Sender reserve is set.
1252  && static_cast<bool>(
1253  flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
1254  static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
1255  !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
1256  !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
1257  // Sender trust limit is 0.
1258  && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1259  // Sender quality in is 0.
1260  &&
1261  !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1262  // Sender quality out is 0.
1263  {
1264  // VFALCO Where is the line being deleted?
1265  // Clear the reserve of the sender, possibly delete the line!
1266  adjustOwnerCount(view, sle, -1, j);
1267 
1268  // Clear reserve flag.
1269  state->setFieldU32(
1270  sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1271 
1272  // Balance is zero, receiver reserve is clear.
1273  if (!after // Balance is zero.
1274  && !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)))
1275  return true;
1276  }
1277  return false;
1278 }
1279 
1280 TER
1282  ApplyView& view,
1283  AccountID const& account,
1284  STAmount const& amount,
1285  Issue const& issue,
1286  beast::Journal j)
1287 {
1288  assert(!isXRP(account) && !isXRP(issue.account));
1289 
1290  // Consistency check
1291  assert(issue == amount.issue());
1292 
1293  // Can't send to self!
1294  assert(issue.account != account);
1295 
1296  JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": "
1297  << amount.getFullText();
1298 
1299  bool bSenderHigh = issue.account > account;
1300 
1301  auto const index = keylet::line(issue.account, account, issue.currency);
1302 
1303  if (auto state = view.peek(index))
1304  {
1305  STAmount final_balance = state->getFieldAmount(sfBalance);
1306 
1307  if (bSenderHigh)
1308  final_balance.negate(); // Put balance in sender terms.
1309 
1310  STAmount const start_balance = final_balance;
1311 
1312  final_balance -= amount;
1313 
1314  auto const must_delete = updateTrustLine(
1315  view,
1316  state,
1317  bSenderHigh,
1318  issue.account,
1319  start_balance,
1320  final_balance,
1321  j);
1322 
1323  view.creditHook(issue.account, account, amount, start_balance);
1324 
1325  if (bSenderHigh)
1326  final_balance.negate();
1327 
1328  // Adjust the balance on the trust line if necessary. We do this even if
1329  // we are going to delete the line to reflect the correct balance at the
1330  // time of deletion.
1331  state->setFieldAmount(sfBalance, final_balance);
1332  if (must_delete)
1333  return trustDelete(
1334  view,
1335  state,
1336  bSenderHigh ? account : issue.account,
1337  bSenderHigh ? issue.account : account,
1338  j);
1339 
1340  view.update(state);
1341 
1342  return tesSUCCESS;
1343  }
1344 
1345  // NIKB TODO: The limit uses the receiver's account as the issuer and
1346  // this is unnecessarily inefficient as copying which could be avoided
1347  // is now required. Consider available options.
1348  STAmount const limit({issue.currency, account});
1349  STAmount final_balance = amount;
1350 
1351  final_balance.setIssuer(noAccount());
1352 
1353  auto const receiverAccount = view.peek(keylet::account(account));
1354  if (!receiverAccount)
1355  return tefINTERNAL;
1356 
1357  bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
1358 
1359  return trustCreate(
1360  view,
1361  bSenderHigh,
1362  issue.account,
1363  account,
1364  index.key,
1365  receiverAccount,
1366  false,
1367  noRipple,
1368  false,
1369  final_balance,
1370  limit,
1371  0,
1372  0,
1373  j);
1374 }
1375 
1376 TER
1378  ApplyView& view,
1379  AccountID const& account,
1380  STAmount const& amount,
1381  Issue const& issue,
1382  beast::Journal j)
1383 {
1384  assert(!isXRP(account) && !isXRP(issue.account));
1385 
1386  // Consistency check
1387  assert(issue == amount.issue());
1388 
1389  // Can't send to self!
1390  assert(issue.account != account);
1391 
1392  JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": "
1393  << amount.getFullText();
1394 
1395  bool bSenderHigh = account > issue.account;
1396 
1397  if (auto state =
1398  view.peek(keylet::line(account, issue.account, issue.currency)))
1399  {
1400  STAmount final_balance = state->getFieldAmount(sfBalance);
1401 
1402  if (bSenderHigh)
1403  final_balance.negate(); // Put balance in sender terms.
1404 
1405  STAmount const start_balance = final_balance;
1406 
1407  final_balance -= amount;
1408 
1409  auto const must_delete = updateTrustLine(
1410  view, state, bSenderHigh, account, start_balance, final_balance, j);
1411 
1412  view.creditHook(account, issue.account, amount, start_balance);
1413 
1414  if (bSenderHigh)
1415  final_balance.negate();
1416 
1417  // Adjust the balance on the trust line if necessary. We do this even if
1418  // we are going to delete the line to reflect the correct balance at the
1419  // time of deletion.
1420  state->setFieldAmount(sfBalance, final_balance);
1421 
1422  if (must_delete)
1423  {
1424  return trustDelete(
1425  view,
1426  state,
1427  bSenderHigh ? issue.account : account,
1428  bSenderHigh ? account : issue.account,
1429  j);
1430  }
1431 
1432  view.update(state);
1433  return tesSUCCESS;
1434  }
1435 
1436  // In order to hold an IOU, a trust line *MUST* exist to track the
1437  // balance. If it doesn't, then something is very wrong. Don't try
1438  // to continue.
1439  JLOG(j.fatal()) << "redeemIOU: " << to_string(account)
1440  << " attempts to redeem " << amount.getFullText()
1441  << " but no trust line exists!";
1442 
1443  return tefINTERNAL;
1444 }
1445 
1446 TER
1448  ApplyView& view,
1449  AccountID const& from,
1450  AccountID const& to,
1451  STAmount const& amount,
1452  beast::Journal j)
1453 {
1454  assert(from != beast::zero);
1455  assert(to != beast::zero);
1456  assert(from != to);
1457  assert(amount.native());
1458 
1459  SLE::pointer const sender = view.peek(keylet::account(from));
1460  SLE::pointer const receiver = view.peek(keylet::account(to));
1461  if (!sender || !receiver)
1462  return tefINTERNAL;
1463 
1464  JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> "
1465  << to_string(to) << ") : " << amount.getFullText();
1466 
1467  if (sender->getFieldAmount(sfBalance) < amount)
1468  {
1469  // VFALCO Its unfortunate we have to keep
1470  // mutating these TER everywhere
1471  // FIXME: this logic should be moved to callers maybe?
1472  return view.open() ? TER{telFAILED_PROCESSING}
1474  }
1475 
1476  // Decrement XRP balance.
1477  sender->setFieldAmount(
1478  sfBalance, sender->getFieldAmount(sfBalance) - amount);
1479  view.update(sender);
1480 
1481  receiver->setFieldAmount(
1482  sfBalance, receiver->getFieldAmount(sfBalance) + amount);
1483  view.update(receiver);
1484 
1485  return tesSUCCESS;
1486 }
1487 
1488 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::ReadView::info
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
ripple::rippleCredit
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Definition: View.cpp:933
ripple::sfIndexNext
const SF_UINT64 sfIndexNext
ripple::sfHighQualityIn
const SF_UINT32 sfHighQualityIn
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition: Indexes.cpp:300
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:471
ripple::cdirNext
bool cdirNext(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the next entry in the directory, advancing the index.
Definition: View.cpp:147
ripple::dirNext
bool dirNext(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:125
ripple::STAmount::negate
void negate()
Definition: STAmount.h:273
ripple::SLE
STLedgerEntry SLE
Definition: STLedgerEntry.h:120
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:621
ripple::Keylet
A pair of SHAMap key and LedgerEntryType.
Definition: Keylet.h:38
ripple::tecNO_TARGET
@ tecNO_TARGET
Definition: TER.h:266
ripple::getEnabledAmendments
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition: View.cpp:604
ripple::STLedgerEntry
Definition: STLedgerEntry.h:30
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:151
ripple::lsfGlobalFreeze
@ lsfGlobalFreeze
Definition: LedgerFormats.h:219
std::string
STL class.
std::shared_ptr
STL class.
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:103
ripple::keylet::amendments
Keylet const & amendments() noexcept
The index of the amendment table.
Definition: Indexes.cpp:160
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:52
ripple::sfOwnerNode
const SF_UINT64 sfOwnerNode
ripple::Rate
Represents a transfer rate.
Definition: Rate.h:37
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::STAmount::clear
void clear()
Definition: STAmount.h:280
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:731
ripple::lsfLowReserve
@ lsfLowReserve
Definition: LedgerFormats.h:229
ripple::STObject::getFieldU64
std::uint64_t getFieldU64(SField const &field) const
Definition: STObject.cpp:538
ripple::sfBookDirectory
const SF_HASH256 sfBookDirectory
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:100
ripple::XRPAmount::drops
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:172
ripple::detail::internalDirNext
bool internalDirNext(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:46
ripple::lsfLowAuth
@ lsfLowAuth
Definition: LedgerFormats.h:231
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s, bool includeHash)
Definition: View.cpp:164
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:233
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
ripple::ReadView::fees
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
ripple::accountHolds
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition: View.cpp:216
ripple::Serializer::add8
int add8(unsigned char i)
Definition: Serializer.cpp:166
ripple::ApplyView::creditHook
virtual void creditHook(AccountID const &from, AccountID const &to, STAmount const &amount, STAmount const &preCreditBalance)
Definition: ApplyView.h:240
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::keylet::skip
Keylet const & skip() noexcept
The index of the "short" skip list.
Definition: Indexes.cpp:142
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::keylet::child
Keylet child(uint256 const &key) noexcept
Any item that can be in an owner dir.
Definition: Indexes.cpp:136
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::ReadView::balanceHook
virtual STAmount balanceHook(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
Definition: ReadView.h:320
ripple::sfCloseTime
const SF_UINT32 sfCloseTime
ripple::sfAmendment
const SF_HASH256 sfAmendment
std::function
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
ripple::STAmount::setIssuer
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:304
ripple::FreezeHandling
FreezeHandling
Controls the treatment of frozen account balances.
Definition: View.h:52
ripple::Serializer::add64
int add64(std::uint64_t i)
Definition: Serializer.cpp:60
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:72
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:101
ripple::parityRate
const Rate parityRate(QUALITY_ONE)
A transfer rate signifying a 1:1 exchange.
Definition: Rate.h:94
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:301
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:139
ripple::lsfHighAuth
@ lsfHighAuth
Definition: LedgerFormats.h:232
ripple::featureDeletableAccounts
const uint256 featureDeletableAccounts
Definition: Feature.cpp:185
ripple::sfIndexes
const SF_VECTOR256 sfIndexes
ripple::forEachItem
void forEachItem(ReadView const &view, AccountID const &id, std::function< void(std::shared_ptr< SLE const > const &)> f)
Iterate all items in an account's owner directory.
Definition: View.cpp:375
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::LedgerInfo::closeTime
NetClock::time_point closeTime
Definition: ReadView.h:123
ripple::STLedgerEntry::key
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
Definition: STLedgerEntry.h:86
ripple::sfLowNode
const SF_UINT64 sfLowNode
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 256 >
ripple::sfLowQualityOut
const SF_UINT32 sfLowQualityOut
ripple::STAmount::getFullText
std::string getFullText() const override
Definition: STAmount.cpp:489
ripple::sfLowLimit
const SF_AMOUNT sfLowLimit
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::isGlobalFrozen
bool isGlobalFrozen(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:181
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::telFAILED_PROCESSING
@ telFAILED_PROCESSING
Definition: TER.h:55
ripple::lsfDefaultRipple
@ lsfDefaultRipple
Definition: LedgerFormats.h:220
ripple::majorityAmendments_t
std::map< uint256, NetClock::time_point > majorityAmendments_t
Definition: View.h:133
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:130
std::enable_if_t
ripple::STObject::setFieldAmount
void setFieldAmount(SField const &field, STAmount const &)
Definition: STObject.cpp:680
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:893
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:562
ripple::TERSubset< CanCvtToTER >
ripple::keylet::page
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:306
ripple::tecFAILED_PROCESSING
@ tecFAILED_PROCESSING
Definition: TER.h:248
ripple::sfBookNode
const SF_UINT64 sfBookNode
ripple::sfLowQualityIn
const SF_UINT32 sfLowQualityIn
ripple::LedgerInfo::closeFlags
int closeFlags
Definition: ReadView.h:114
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:555
ripple::accountSend
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j)
Definition: View.cpp:1122
ripple::STAmount
Definition: STAmount.h:43
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:90
beast::Journal::Stream
Provide a light-weight way to check active() before string formatting.
Definition: Journal.h:194
ripple::xrpLiquid
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Definition: View.cpp:339
ripple::hashOfSeq
std::optional< uint256 > hashOfSeq(ReadView const &ledger, LedgerIndex seq, beast::Journal journal)
Return the hash of a ledger by sequence.
Definition: View.cpp:644
ripple::sfTransferRate
const SF_UINT32 sfTransferRate
ripple::STVector256::size
std::size_t size() const
Definition: STVector256.h:110
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::ValStatus::current
@ current
This was a new validation and was added.
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::sfHighLimit
const SF_AMOUNT sfHighLimit
ripple::Rules::enabled
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Definition: ReadView.cpp:102
ripple::keylet::line
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:190
ripple::rippleSend
static TER rippleSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j)
Definition: View.cpp:1078
std::map
STL class.
ripple::ApplyView::adjustOwnerCountHook
virtual void adjustOwnerCountHook(AccountID const &account, std::uint32_t cur, std::uint32_t next)
Definition: ApplyView.h:251
ripple::trustDelete
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
Definition: View.cpp:853
ripple::ReadView::read
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
ripple::areCompatible
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, const char *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
Definition: View.cpp:482
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:260
ripple::STAmount::getCurrency
Currency const & getCurrency() const
Definition: STAmount.h:205
ripple::LedgerInfo::drops
XRPAmount drops
Definition: ReadView.h:105
ripple::transferXRP
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
Definition: View.cpp:1447
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:234
ripple::STAmount::getIssuer
AccountID const & getIssuer() const
Definition: STAmount.h:210
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:249
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:38
ripple::Serializer
Definition: Serializer.h:39
ripple::lsfHighFreeze
@ lsfHighFreeze
Definition: LedgerFormats.h:236
ripple::sfHashes
const SF_VECTOR256 sfHashes
ripple::issueIOU
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1281
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:183
ripple::dirIsEmpty
bool dirIsEmpty(ReadView const &view, Keylet const &k)
Returns true if the directory is empty.
Definition: View.cpp:590
ripple::ReadView
A view into a ledger.
Definition: ReadView.h:192
ripple::ApplyView::insert
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::dirFirst
bool dirFirst(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:114
ripple::trustCreate
TER trustCreate(ApplyView &view, const bool bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, const bool bAuth, const bool bNoRipple, const bool bFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
Definition: View.cpp:739
ripple::Fees::accountReserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: ReadView.h:66
ripple::ReadView::seq
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition: ReadView.h:260
ripple::base_uint::zero
void zero()
Definition: base_uint.h:521
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1377
ripple::ReadView::rules
virtual Rules const & rules() const =0
Returns the tx processing rules.
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:198
ripple::sfFlags
const SF_UINT32 sfFlags
ripple::LedgerInfo::closeTimeResolution
NetClock::duration closeTimeResolution
Definition: ReadView.h:117
cassert
ripple::ReadView::ownerCountHook
virtual std::uint32_t ownerCountHook(AccountID const &account, std::uint32_t count) const
Definition: ReadView.h:334
ripple::sfBalance
const SF_AMOUNT sfBalance
std::chrono::duration::count
T count(T... args)
ripple::STVector256
Definition: STVector256.h:29
ripple::detail::internalDirFirst
bool internalDirFirst(V &view, uint256 const &root, std::shared_ptr< N > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:92
ripple::forEachItemAfter
bool forEachItemAfter(ReadView const &view, AccountID const &id, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> f)
Iterate all items after an item in an owner directory.
Definition: View.cpp:398
ripple::confineOwnerCount
static std::uint32_t confineOwnerCount(std::uint32_t current, std::int32_t adjustment, std::optional< AccountID > const &id=std::nullopt, beast::Journal j=beast::Journal{beast::Journal::getNullSink()})
Definition: View.cpp:301
ripple::sfHighQualityOut
const SF_UINT32 sfHighQualityOut
optional
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
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::sfAccount
const SF_ACCOUNT sfAccount
ripple::ltRIPPLE_STATE
@ ltRIPPLE_STATE
A ledger object which describes a bidirectional trust line.
Definition: LedgerFormats.h:74
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::LedgerInfo
Information about the notional ledger backing the view.
Definition: ReadView.h:84
ripple::lsfLowFreeze
@ lsfLowFreeze
Definition: LedgerFormats.h:235
std::numeric_limits::max
T max(T... args)
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:532
ripple::updateTrustLine
static bool updateTrustLine(ApplyView &view, SLE::pointer state, bool bSenderHigh, AccountID const &sender, STAmount const &before, STAmount const &after, beast::Journal j)
Definition: View.cpp:1228
ripple::sfLastLedgerSequence
const SF_UINT32 sfLastLedgerSequence
ripple::ApplyView::dirInsert
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
Definition: ApplyView.h:311
ripple::cdirFirst
bool cdirFirst(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the first entry in the directory, advancing the index.
Definition: View.cpp:136
ripple::STLedgerEntry::ref
const std::shared_ptr< STLedgerEntry > & ref
Definition: STLedgerEntry.h:36
ripple::sfMajorities
const SField sfMajorities
ripple::ReadView::open
virtual bool open() const =0
Returns true if this reflects an open ledger.
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:56
ripple::lsfHighReserve
@ lsfHighReserve
Definition: LedgerFormats.h:230
ripple::STObject::setFieldU32
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:632
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:217
std::set
STL class.
ripple::sfHighNode
const SF_UINT64 sfHighNode
ripple::isFrozen
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:193
ripple::STObject::getFieldAmount
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:576
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:97
ripple::STLedgerEntry::pointer
std::shared_ptr< STLedgerEntry > pointer
Definition: STLedgerEntry.h:35
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:102
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::sfAmendments
const SF_VECTOR256 sfAmendments
ripple::LedgerInfo::parentCloseTime
NetClock::time_point parentCloseTime
Definition: ReadView.h:93
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:556