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