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/chrono.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/ledger/ReadView.h>
24 #include <ripple/ledger/View.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/Protocol.h>
27 #include <ripple/protocol/Quality.h>
28 #include <ripple/protocol/st.h>
29 #include <cassert>
30 #include <optional>
31 
32 namespace ripple {
33 
34 namespace detail {
35 
36 template <
37  class V,
38  class N,
39  class = std::enable_if_t<
40  std::is_same_v<std::remove_cv_t<N>, SLE> &&
41  std::is_base_of_v<ReadView, V>>>
42 bool
44  V& view,
45  uint256 const& root,
46  std::shared_ptr<N>& page,
47  unsigned int& index,
48  uint256& entry)
49 {
50  auto const& svIndexes = page->getFieldV256(sfIndexes);
51  assert(index <= svIndexes.size());
52 
53  if (index >= svIndexes.size())
54  {
55  auto const next = page->getFieldU64(sfIndexNext);
56 
57  if (!next)
58  {
59  entry.zero();
60  return false;
61  }
62 
63  if constexpr (std::is_const_v<N>)
64  page = view.read(keylet::page(root, next));
65  else
66  page = view.peek(keylet::page(root, next));
67 
68  assert(page);
69 
70  if (!page)
71  return false;
72 
73  index = 0;
74 
75  return internalDirNext(view, root, page, index, entry);
76  }
77 
78  entry = svIndexes[index++];
79  return true;
80 }
81 
82 template <
83  class V,
84  class N,
85  class = std::enable_if_t<
86  std::is_same_v<std::remove_cv_t<N>, SLE> &&
87  std::is_base_of_v<ReadView, V>>>
88 bool
90  V& view,
91  uint256 const& root,
92  std::shared_ptr<N>& page,
93  unsigned int& index,
94  uint256& entry)
95 {
96  if constexpr (std::is_const_v<N>)
97  page = view.read(keylet::page(root));
98  else
99  page = view.peek(keylet::page(root));
100 
101  if (!page)
102  return false;
103 
104  index = 0;
105 
106  return internalDirNext(view, root, page, index, entry);
107 }
108 
109 } // namespace detail
110 
111 bool
113  ApplyView& view,
114  uint256 const& root,
115  std::shared_ptr<SLE>& page,
116  unsigned int& index,
117  uint256& entry)
118 {
119  return detail::internalDirFirst(view, root, page, index, entry);
120 }
121 
122 bool
124  ApplyView& view,
125  uint256 const& root,
126  std::shared_ptr<SLE>& page,
127  unsigned int& index,
128  uint256& entry)
129 {
130  return detail::internalDirNext(view, root, page, index, entry);
131 }
132 
133 bool
135  ReadView const& view,
136  uint256 const& root,
138  unsigned int& index,
139  uint256& entry)
140 {
141  return detail::internalDirFirst(view, root, page, index, entry);
142 }
143 
144 bool
146  ReadView const& view,
147  uint256 const& root,
149  unsigned int& index,
150  uint256& entry)
151 {
152  return detail::internalDirNext(view, root, page, index, entry);
153 }
154 
155 //------------------------------------------------------------------------------
156 //
157 // Observers
158 //
159 //------------------------------------------------------------------------------
160 
161 void
162 addRaw(LedgerInfo const& info, Serializer& s, bool includeHash)
163 {
164  s.add32(info.seq);
165  s.add64(info.drops.drops());
166  s.addBitString(info.parentHash);
167  s.addBitString(info.txHash);
168  s.addBitString(info.accountHash);
169  s.add32(info.parentCloseTime.time_since_epoch().count());
170  s.add32(info.closeTime.time_since_epoch().count());
171  s.add8(info.closeTimeResolution.count());
172  s.add8(info.closeFlags);
173 
174  if (includeHash)
175  s.addBitString(info.hash);
176 }
177 
178 bool
180 {
181  using d = NetClock::duration;
182  using tp = NetClock::time_point;
183 
184  return exp && (view.parentCloseTime() >= tp{d{*exp}});
185 }
186 
187 bool
188 isGlobalFrozen(ReadView const& view, AccountID const& issuer)
189 {
190  if (isXRP(issuer))
191  return false;
192  if (auto const sle = view.read(keylet::account(issuer)))
193  return sle->isFlag(lsfGlobalFreeze);
194  return false;
195 }
196 
197 // Can the specified account spend the specified currency issued by
198 // the specified issuer or does the freeze flag prohibit it?
199 bool
201  ReadView const& view,
202  AccountID const& account,
203  Currency const& currency,
204  AccountID const& issuer)
205 {
206  if (isXRP(currency))
207  return false;
208  auto sle = view.read(keylet::account(issuer));
209  if (sle && sle->isFlag(lsfGlobalFreeze))
210  return true;
211  if (issuer != account)
212  {
213  // Check if the issuer froze the line
214  sle = view.read(keylet::line(account, issuer, currency));
215  if (sle &&
216  sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
217  return true;
218  }
219  return false;
220 }
221 
222 STAmount
224  ReadView const& view,
225  AccountID const& account,
226  Currency const& currency,
227  AccountID const& issuer,
228  FreezeHandling zeroIfFrozen,
229  beast::Journal j)
230 {
231  STAmount amount;
232  if (isXRP(currency))
233  {
234  return {xrpLiquid(view, account, 0, j)};
235  }
236 
237  // IOU: Return balance on trust line modulo freeze
238  auto const sle = view.read(keylet::line(account, issuer, currency));
239  if (!sle)
240  {
241  amount.clear({currency, issuer});
242  }
243  else if (
244  (zeroIfFrozen == fhZERO_IF_FROZEN) &&
245  isFrozen(view, account, currency, issuer))
246  {
247  amount.clear(Issue(currency, issuer));
248  }
249  else
250  {
251  amount = sle->getFieldAmount(sfBalance);
252  if (account > issuer)
253  {
254  // Put balance in account terms.
255  amount.negate();
256  }
257  amount.setIssuer(issuer);
258  }
259  JLOG(j.trace()) << "accountHolds:"
260  << " account=" << to_string(account)
261  << " amount=" << amount.getFullText();
262 
263  return view.balanceHook(account, issuer, amount);
264 }
265 
266 STAmount
268  ReadView const& view,
269  AccountID const& id,
270  STAmount const& saDefault,
271  FreezeHandling freezeHandling,
272  beast::Journal j)
273 {
274  if (!saDefault.native() && saDefault.getIssuer() == id)
275  return saDefault;
276 
277  return accountHolds(
278  view,
279  id,
280  saDefault.getCurrency(),
281  saDefault.getIssuer(),
282  freezeHandling,
283  j);
284 }
285 
286 // Prevent ownerCount from wrapping under error conditions.
287 //
288 // adjustment allows the ownerCount to be adjusted up or down in multiple steps.
289 // If id != std::nullopt, then do error reporting.
290 //
291 // Returns adjusted owner count.
292 static std::uint32_t
294  std::uint32_t current,
295  std::int32_t adjustment,
296  std::optional<AccountID> const& id = std::nullopt,
298 {
299  std::uint32_t adjusted{current + adjustment};
300  if (adjustment > 0)
301  {
302  // Overflow is well defined on unsigned
303  if (adjusted < current)
304  {
305  if (id)
306  {
307  JLOG(j.fatal())
308  << "Account " << *id << " owner count exceeds max!";
309  }
311  }
312  }
313  else
314  {
315  // Underflow is well defined on unsigned
316  if (adjusted > current)
317  {
318  if (id)
319  {
320  JLOG(j.fatal())
321  << "Account " << *id << " owner count set below 0!";
322  }
323  adjusted = 0;
324  assert(!id);
325  }
326  }
327  return adjusted;
328 }
329 
330 XRPAmount
332  ReadView const& view,
333  AccountID const& id,
334  std::int32_t ownerCountAdj,
335  beast::Journal j)
336 {
337  auto const sle = view.read(keylet::account(id));
338  if (sle == nullptr)
339  return beast::zero;
340 
341  // Return balance minus reserve
342  std::uint32_t const ownerCount = confineOwnerCount(
343  view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
344 
345  auto const reserve = view.fees().accountReserve(ownerCount);
346 
347  auto const fullBalance = sle->getFieldAmount(sfBalance);
348 
349  auto const balance = view.balanceHook(id, xrpAccount(), fullBalance);
350 
351  STAmount amount = balance - reserve;
352  if (balance < reserve)
353  amount.clear();
354 
355  JLOG(j.trace()) << "accountHolds:"
356  << " account=" << to_string(id)
357  << " amount=" << amount.getFullText()
358  << " fullBalance=" << fullBalance.getFullText()
359  << " balance=" << balance.getFullText()
360  << " reserve=" << reserve << " ownerCount=" << ownerCount
361  << " ownerCountAdj=" << ownerCountAdj;
362 
363  return amount.xrp();
364 }
365 
366 void
368  ReadView const& view,
369  Keylet const& root,
370  std::function<void(std::shared_ptr<SLE const> const&)> const& f)
371 {
372  assert(root.type == ltDIR_NODE);
373 
374  if (root.type != ltDIR_NODE)
375  return;
376 
377  auto pos = root;
378 
379  while (true)
380  {
381  auto sle = view.read(pos);
382  if (!sle)
383  return;
384  for (auto const& key : sle->getFieldV256(sfIndexes))
385  f(view.read(keylet::child(key)));
386  auto const next = sle->getFieldU64(sfIndexNext);
387  if (!next)
388  return;
389  pos = keylet::page(root, next);
390  }
391 }
392 
393 bool
395  ReadView const& view,
396  Keylet const& root,
397  uint256 const& after,
398  std::uint64_t const hint,
399  unsigned int limit,
400  std::function<bool(std::shared_ptr<SLE const> const&)> const& f)
401 {
402  assert(root.type == ltDIR_NODE);
403 
404  if (root.type != ltDIR_NODE)
405  return false;
406 
407  auto currentIndex = root;
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(root, hint);
413 
414  if (auto hintDir = view.read(hintIndex))
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(root, 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(root, 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:303
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:145
ripple::dirNext
bool dirNext(ApplyView &view, uint256 const &root, std::shared_ptr< SLE > &page, unsigned int &index, uint256 &entry)
Definition: View.cpp:123
ripple::STAmount::negate
void negate()
Definition: STAmount.h:402
ripple::STLedgerEntry::key
uint256 const & key() const
Returns the 'key' (or 'index') of this item.
Definition: STLedgerEntry.h:113
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:271
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:155
ripple::lsfGlobalFreeze
@ lsfGlobalFreeze
Definition: LedgerFormats.h:231
std::string
STL class.
ripple::Rules::enabled
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:94
std::shared_ptr
STL class.
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:94
ripple::keylet::amendments
Keylet const & amendments() noexcept
The index of the amendment table.
Definition: Indexes.cpp:163
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:76
ripple::forEachItemAfter
bool forEachItemAfter(ReadView const &view, Keylet const &root, uint256 const &after, std::uint64_t const hint, unsigned int limit, std::function< bool(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items after an item in the given directory.
Definition: View.cpp:394
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:409
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:347
ripple::describeOwnerDir
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition: View.cpp:731
ripple::lsfLowReserve
@ lsfLowReserve
Definition: LedgerFormats.h:252
ripple::STObject::getFieldU64
std::uint64_t getFieldU64(SField const &field) const
Definition: STObject.cpp:565
ripple::sfOwner
const SF_ACCOUNT sfOwner
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:91
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:43
ripple::lsfLowAuth
@ lsfLowAuth
Definition: LedgerFormats.h:254
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s, bool includeHash)
Definition: View.cpp:162
ripple::lsfLowNoRipple
@ lsfLowNoRipple
Definition: LedgerFormats.h:256
ripple::ApplyView::erase
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
ripple::sfBookDirectory
const SF_UINT256 sfBookDirectory
ripple::SLE
STLedgerEntry SLE
Definition: Application.h:66
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:223
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:235
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:145
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:139
ripple::ApplyView::update
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
ripple::hasExpired
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
Definition: View.cpp:179
ripple::ReadView::balanceHook
virtual STAmount balanceHook(AccountID const &account, AccountID const &issuer, STAmount const &amount) const
Definition: ReadView.h:253
ripple::sfCloseTime
const SF_UINT32 sfCloseTime
std::function
ripple::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:83
ripple::STAmount::setIssuer
void setIssuer(AccountID const &uIssuer)
Definition: STAmount.h:433
ripple::ReadView::parentCloseTime
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
Definition: ReadView.h:186
ripple::FreezeHandling
FreezeHandling
Controls the treatment of frozen account balances.
Definition: View.h:76
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:92
ripple::parityRate
const Rate parityRate(QUALITY_ONE)
A transfer rate signifying a 1:1 exchange.
Definition: Rate.h:101
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:334
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:134
ripple::lsfHighAuth
@ lsfHighAuth
Definition: LedgerFormats.h:255
ripple::ltDIR_NODE
@ ltDIR_NODE
A ledger object which contains a list of object identifiers.
Definition: LedgerFormats.h:66
ripple::STAmount::getIssuer
AccountID const & getIssuer() const
Definition: STAmount.h:359
ripple::featureDeletableAccounts
const uint256 featureDeletableAccounts
ripple::sfIndexes
const SF_VECTOR256 sfIndexes
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:114
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:548
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:188
ripple::tefBAD_LEDGER
@ tefBAD_LEDGER
Definition: TER.h:152
ripple::adjustOwnerCount
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition: View.cpp:713
ripple::telFAILED_PROCESSING
@ telFAILED_PROCESSING
Definition: TER.h:55
ripple::lsfDefaultRipple
@ lsfDefaultRipple
Definition: LedgerFormats.h:232
ripple::majorityAmendments_t
std::map< uint256, NetClock::time_point > majorityAmendments_t
Definition: View.h:190
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
std::enable_if_t
ripple::STObject::setFieldAmount
void setFieldAmount(SField const &field, STAmount const &)
Definition: STObject.cpp:707
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:589
ripple::TERSubset< CanCvtToTER >
ripple::keylet::page
Keylet page(uint256 const &key, std::uint64_t index) noexcept
A page in a directory.
Definition: Indexes.cpp:309
ripple::tecFAILED_PROCESSING
@ tecFAILED_PROCESSING
Definition: TER.h:253
ripple::sfBookNode
const SF_UINT64 sfBookNode
ripple::sfLowQualityIn
const SF_UINT32 sfLowQualityIn
ripple::LedgerInfo::closeFlags
int closeFlags
Definition: ReadView.h:105
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:568
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:45
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:168
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:331
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:166
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::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:193
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:246
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:267
ripple::LedgerInfo::drops
XRPAmount drops
Definition: ReadView.h:96
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:257
ripple::tecDIR_FULL
@ tecDIR_FULL
Definition: TER.h:254
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::Serializer
Definition: Serializer.h:39
ripple::lsfHighFreeze
@ lsfHighFreeze
Definition: LedgerFormats.h:259
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:329
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:125
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:112
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:193
ripple::base_uint::zero
void zero()
Definition: base_uint.h:542
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::sfFlags
const SF_UINT32 sfFlags
ripple::LedgerInfo::closeTimeResolution
NetClock::duration closeTimeResolution
Definition: ReadView.h:108
cassert
ripple::ReadView::ownerCountHook
virtual std::uint32_t ownerCountHook(AccountID const &account, std::uint32_t count) const
Definition: ReadView.h:267
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:89
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:293
ripple::sfHighQualityOut
const SF_UINT32 sfHighQualityOut
optional
ripple::forEachItem
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Definition: View.cpp:367
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:41
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:75
ripple::lsfLowFreeze
@ lsfLowFreeze
Definition: LedgerFormats.h:258
ripple::NetClock::duration
std::chrono::duration< rep, period > duration
Definition: chrono.h:55
std::numeric_limits::max
T max(T... args)
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:559
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:306
ripple::sfAmendment
const SF_UINT256 sfAmendment
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:134
ripple::STLedgerEntry::ref
const std::shared_ptr< STLedgerEntry > & ref
Definition: STLedgerEntry.h:37
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:253
ripple::STObject::setFieldU32
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:659
ripple::STAmount::getCurrency
Currency const & getCurrency() const
Definition: STAmount.h:353
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
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:200
ripple::STObject::getFieldAmount
STAmount const & getFieldAmount(SField const &field) const
Definition: STObject.cpp:603
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
ripple::STLedgerEntry::pointer
std::shared_ptr< STLedgerEntry > pointer
Definition: STLedgerEntry.h:36
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:93
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:84
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:583
ripple::root
Number root(Number f, unsigned d)
Definition: Number.cpp:624