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