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 
726  ApplyView& view,
727  Keylet const& dir,
728  uint256 const& uLedgerIndex,
729  bool strictOrder,
730  std::function<void(SLE::ref)> fDescriber,
731  beast::Journal j)
732 {
733  if (strictOrder)
734  return view.dirAppend(dir, uLedgerIndex, fDescriber);
735 
736  return view.dirInsert(dir, uLedgerIndex, fDescriber);
737 }
738 
739 TER
741  ApplyView& view,
742  const bool bSrcHigh,
743  AccountID const& uSrcAccountID,
744  AccountID const& uDstAccountID,
745  uint256 const& uIndex, // --> ripple state entry
746  SLE::ref sleAccount, // --> the account being set.
747  const bool bAuth, // --> authorize account.
748  const bool bNoRipple, // --> others cannot ripple through
749  const bool bFreeze, // --> funds cannot leave
750  STAmount const& saBalance, // --> balance of account being set.
751  // Issuer should be noAccount()
752  STAmount const& saLimit, // --> limit for account being set.
753  // Issuer should be the account being set.
754  std::uint32_t uQualityIn,
755  std::uint32_t uQualityOut,
756  beast::Journal j)
757 {
758  JLOG(j.trace()) << "trustCreate: " << to_string(uSrcAccountID) << ", "
759  << to_string(uDstAccountID) << ", "
760  << saBalance.getFullText();
761 
762  auto const& uLowAccountID = !bSrcHigh ? uSrcAccountID : uDstAccountID;
763  auto const& uHighAccountID = bSrcHigh ? uSrcAccountID : uDstAccountID;
764 
765  auto const sleRippleState = std::make_shared<SLE>(ltRIPPLE_STATE, uIndex);
766  view.insert(sleRippleState);
767 
768  auto lowNode = dirAdd(
769  view,
770  keylet::ownerDir(uLowAccountID),
771  sleRippleState->key(),
772  false,
773  describeOwnerDir(uLowAccountID),
774  j);
775 
776  if (!lowNode)
777  return tecDIR_FULL;
778 
779  auto highNode = dirAdd(
780  view,
781  keylet::ownerDir(uHighAccountID),
782  sleRippleState->key(),
783  false,
784  describeOwnerDir(uHighAccountID),
785  j);
786 
787  if (!highNode)
788  return tecDIR_FULL;
789 
790  const bool bSetDst = saLimit.getIssuer() == uDstAccountID;
791  const bool bSetHigh = bSrcHigh ^ bSetDst;
792 
793  assert(sleAccount);
794  if (!sleAccount)
795  return tefINTERNAL;
796 
797  assert(
798  sleAccount->getAccountID(sfAccount) ==
799  (bSetHigh ? uHighAccountID : uLowAccountID));
800  auto const slePeer =
801  view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
802  if (!slePeer)
803  return tecNO_TARGET;
804 
805  // Remember deletion hints.
806  sleRippleState->setFieldU64(sfLowNode, *lowNode);
807  sleRippleState->setFieldU64(sfHighNode, *highNode);
808 
809  sleRippleState->setFieldAmount(
810  bSetHigh ? sfHighLimit : sfLowLimit, saLimit);
811  sleRippleState->setFieldAmount(
812  bSetHigh ? sfLowLimit : sfHighLimit,
813  STAmount(
814  {saBalance.getCurrency(),
815  bSetDst ? uSrcAccountID : uDstAccountID}));
816 
817  if (uQualityIn)
818  sleRippleState->setFieldU32(
819  bSetHigh ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
820 
821  if (uQualityOut)
822  sleRippleState->setFieldU32(
823  bSetHigh ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
824 
825  std::uint32_t uFlags = bSetHigh ? lsfHighReserve : lsfLowReserve;
826 
827  if (bAuth)
828  {
829  uFlags |= (bSetHigh ? lsfHighAuth : lsfLowAuth);
830  }
831  if (bNoRipple)
832  {
833  uFlags |= (bSetHigh ? lsfHighNoRipple : lsfLowNoRipple);
834  }
835  if (bFreeze)
836  {
837  uFlags |= (!bSetHigh ? lsfLowFreeze : lsfHighFreeze);
838  }
839 
840  if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
841  {
842  // The other side's default is no rippling
843  uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
844  }
845 
846  sleRippleState->setFieldU32(sfFlags, uFlags);
847  adjustOwnerCount(view, sleAccount, 1, j);
848 
849  // ONLY: Create ripple balance.
850  sleRippleState->setFieldAmount(
851  sfBalance, bSetHigh ? -saBalance : saBalance);
852 
853  view.creditHook(
854  uSrcAccountID, uDstAccountID, saBalance, saBalance.zeroed());
855 
856  return tesSUCCESS;
857 }
858 
859 TER
861  ApplyView& view,
862  std::shared_ptr<SLE> const& sleRippleState,
863  AccountID const& uLowAccountID,
864  AccountID const& uHighAccountID,
865  beast::Journal j)
866 {
867  // Detect legacy dirs.
868  std::uint64_t uLowNode = sleRippleState->getFieldU64(sfLowNode);
869  std::uint64_t uHighNode = sleRippleState->getFieldU64(sfHighNode);
870 
871  JLOG(j.trace()) << "trustDelete: Deleting ripple line: low";
872 
873  if (!view.dirRemove(
874  keylet::ownerDir(uLowAccountID),
875  uLowNode,
876  sleRippleState->key(),
877  false))
878  {
879  return tefBAD_LEDGER;
880  }
881 
882  JLOG(j.trace()) << "trustDelete: Deleting ripple line: high";
883 
884  if (!view.dirRemove(
885  keylet::ownerDir(uHighAccountID),
886  uHighNode,
887  sleRippleState->key(),
888  false))
889  {
890  return tefBAD_LEDGER;
891  }
892 
893  JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
894  view.erase(sleRippleState);
895 
896  return tesSUCCESS;
897 }
898 
899 TER
901 {
902  if (!sle)
903  return tesSUCCESS;
904  auto offerIndex = sle->key();
905  auto owner = sle->getAccountID(sfAccount);
906 
907  // Detect legacy directories.
908  uint256 uDirectory = sle->getFieldH256(sfBookDirectory);
909 
910  if (!view.dirRemove(
911  keylet::ownerDir(owner),
912  sle->getFieldU64(sfOwnerNode),
913  offerIndex,
914  false))
915  {
916  return tefBAD_LEDGER;
917  }
918 
919  if (!view.dirRemove(
920  keylet::page(uDirectory),
921  sle->getFieldU64(sfBookNode),
922  offerIndex,
923  false))
924  {
925  return tefBAD_LEDGER;
926  }
927 
928  adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j);
929 
930  view.erase(sle);
931 
932  return tesSUCCESS;
933 }
934 
935 // Direct send w/o fees:
936 // - Redeeming IOUs and/or sending sender's own IOUs.
937 // - Create trust line if needed.
938 // --> bCheckIssuer : normally require issuer to be involved.
939 TER
941  ApplyView& view,
942  AccountID const& uSenderID,
943  AccountID const& uReceiverID,
944  STAmount const& saAmount,
945  bool bCheckIssuer,
946  beast::Journal j)
947 {
948  AccountID const& issuer = saAmount.getIssuer();
949  Currency const& currency = saAmount.getCurrency();
950 
951  // Make sure issuer is involved.
952  assert(!bCheckIssuer || uSenderID == issuer || uReceiverID == issuer);
953  (void)issuer;
954 
955  // Disallow sending to self.
956  assert(uSenderID != uReceiverID);
957 
958  bool const bSenderHigh = uSenderID > uReceiverID;
959  auto const index = keylet::line(uSenderID, uReceiverID, currency);
960 
961  assert(!isXRP(uSenderID) && uSenderID != noAccount());
962  assert(!isXRP(uReceiverID) && uReceiverID != noAccount());
963 
964  // If the line exists, modify it accordingly.
965  if (auto const sleRippleState = view.peek(index))
966  {
967  STAmount saBalance = sleRippleState->getFieldAmount(sfBalance);
968 
969  if (bSenderHigh)
970  saBalance.negate(); // Put balance in sender terms.
971 
972  view.creditHook(uSenderID, uReceiverID, saAmount, saBalance);
973 
974  STAmount const saBefore = saBalance;
975 
976  saBalance -= saAmount;
977 
978  JLOG(j.trace()) << "rippleCredit: " << to_string(uSenderID) << " -> "
979  << to_string(uReceiverID)
980  << " : before=" << saBefore.getFullText()
981  << " amount=" << saAmount.getFullText()
982  << " after=" << saBalance.getFullText();
983 
984  std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags));
985  bool bDelete = false;
986 
987  // FIXME This NEEDS to be cleaned up and simplified. It's impossible
988  // for anyone to understand.
989  if (saBefore > beast::zero
990  // Sender balance was positive.
991  && saBalance <= beast::zero
992  // Sender is zero or negative.
993  && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
994  // Sender reserve is set.
995  &&
996  static_cast<bool>(
997  uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
998  static_cast<bool>(
999  view.read(keylet::account(uSenderID))->getFlags() &
1000  lsfDefaultRipple) &&
1001  !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
1002  !sleRippleState->getFieldAmount(
1003  !bSenderHigh ? sfLowLimit : sfHighLimit)
1004  // Sender trust limit is 0.
1005  && !sleRippleState->getFieldU32(
1006  !bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1007  // Sender quality in is 0.
1008  && !sleRippleState->getFieldU32(
1009  !bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1010  // Sender quality out is 0.
1011  {
1012  // Clear the reserve of the sender, possibly delete the line!
1014  view, view.peek(keylet::account(uSenderID)), -1, j);
1015 
1016  // Clear reserve flag.
1017  sleRippleState->setFieldU32(
1018  sfFlags,
1019  uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1020 
1021  // Balance is zero, receiver reserve is clear.
1022  bDelete = !saBalance // Balance is zero.
1023  && !(uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve));
1024  // Receiver reserve is clear.
1025  }
1026 
1027  if (bSenderHigh)
1028  saBalance.negate();
1029 
1030  // Want to reflect balance to zero even if we are deleting line.
1031  sleRippleState->setFieldAmount(sfBalance, saBalance);
1032  // ONLY: Adjust ripple balance.
1033 
1034  if (bDelete)
1035  {
1036  return trustDelete(
1037  view,
1038  sleRippleState,
1039  bSenderHigh ? uReceiverID : uSenderID,
1040  !bSenderHigh ? uReceiverID : uSenderID,
1041  j);
1042  }
1043 
1044  view.update(sleRippleState);
1045  return tesSUCCESS;
1046  }
1047 
1048  STAmount const saReceiverLimit({currency, uReceiverID});
1049  STAmount saBalance{saAmount};
1050 
1051  saBalance.setIssuer(noAccount());
1052 
1053  JLOG(j.debug()) << "rippleCredit: "
1054  "create line: "
1055  << to_string(uSenderID) << " -> " << to_string(uReceiverID)
1056  << " : " << saAmount.getFullText();
1057 
1058  auto const sleAccount = view.peek(keylet::account(uReceiverID));
1059  if (!sleAccount)
1060  return tefINTERNAL;
1061 
1062  bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
1063 
1064  return trustCreate(
1065  view,
1066  bSenderHigh,
1067  uSenderID,
1068  uReceiverID,
1069  index.key,
1070  sleAccount,
1071  false,
1072  noRipple,
1073  false,
1074  saBalance,
1075  saReceiverLimit,
1076  0,
1077  0,
1078  j);
1079 }
1080 
1081 // Send regardless of limits.
1082 // --> saAmount: Amount/currency/issuer to deliver to receiver.
1083 // <-- saActual: Amount actually cost. Sender pays fees.
1084 static TER
1086  ApplyView& view,
1087  AccountID const& uSenderID,
1088  AccountID const& uReceiverID,
1089  STAmount const& saAmount,
1090  STAmount& saActual,
1091  beast::Journal j)
1092 {
1093  auto const issuer = saAmount.getIssuer();
1094 
1095  assert(!isXRP(uSenderID) && !isXRP(uReceiverID));
1096  assert(uSenderID != uReceiverID);
1097 
1098  if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount())
1099  {
1100  // Direct send: redeeming IOUs and/or sending own IOUs.
1101  auto const ter =
1102  rippleCredit(view, uSenderID, uReceiverID, saAmount, false, j);
1103  if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS)
1104  return ter;
1105  saActual = saAmount;
1106  return tesSUCCESS;
1107  }
1108 
1109  // Sending 3rd party IOUs: transit.
1110 
1111  // Calculate the amount to transfer accounting
1112  // for any transfer fees:
1113  saActual = multiply(saAmount, transferRate(view, issuer));
1114 
1115  JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > "
1116  << to_string(uReceiverID)
1117  << " : deliver=" << saAmount.getFullText()
1118  << " cost=" << saActual.getFullText();
1119 
1120  TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j);
1121 
1122  if (tesSUCCESS == terResult)
1123  terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j);
1124 
1125  return terResult;
1126 }
1127 
1128 TER
1130  ApplyView& view,
1131  AccountID const& uSenderID,
1132  AccountID const& uReceiverID,
1133  STAmount const& saAmount,
1134  beast::Journal j)
1135 {
1136  assert(saAmount >= beast::zero);
1137 
1138  /* If we aren't sending anything or if the sender is the same as the
1139  * receiver then we don't need to do anything.
1140  */
1141  if (!saAmount || (uSenderID == uReceiverID))
1142  return tesSUCCESS;
1143 
1144  if (!saAmount.native())
1145  {
1146  STAmount saActual;
1147 
1148  JLOG(j.trace()) << "accountSend: " << to_string(uSenderID) << " -> "
1149  << to_string(uReceiverID) << " : "
1150  << saAmount.getFullText();
1151 
1152  return rippleSend(view, uSenderID, uReceiverID, saAmount, saActual, j);
1153  }
1154 
1155  /* XRP send which does not check reserve and can do pure adjustment.
1156  * Note that sender or receiver may be null and this not a mistake; this
1157  * setup is used during pathfinding and it is carefully controlled to
1158  * ensure that transfers are balanced.
1159  */
1160  TER terResult(tesSUCCESS);
1161 
1162  SLE::pointer sender = uSenderID != beast::zero
1163  ? view.peek(keylet::account(uSenderID))
1164  : SLE::pointer();
1165  SLE::pointer receiver = uReceiverID != beast::zero
1166  ? view.peek(keylet::account(uReceiverID))
1167  : SLE::pointer();
1168 
1169  if (auto stream = j.trace())
1170  {
1171  std::string sender_bal("-");
1172  std::string receiver_bal("-");
1173 
1174  if (sender)
1175  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1176 
1177  if (receiver)
1178  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1179 
1180  stream << "accountSend> " << to_string(uSenderID) << " (" << sender_bal
1181  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1182  << ") : " << saAmount.getFullText();
1183  }
1184 
1185  if (sender)
1186  {
1187  if (sender->getFieldAmount(sfBalance) < saAmount)
1188  {
1189  // VFALCO Its laborious to have to mutate the
1190  // TER based on params everywhere
1191  terResult = view.open() ? TER{telFAILED_PROCESSING}
1193  }
1194  else
1195  {
1196  auto const sndBal = sender->getFieldAmount(sfBalance);
1197  view.creditHook(uSenderID, xrpAccount(), saAmount, sndBal);
1198 
1199  // Decrement XRP balance.
1200  sender->setFieldAmount(sfBalance, sndBal - saAmount);
1201  view.update(sender);
1202  }
1203  }
1204 
1205  if (tesSUCCESS == terResult && receiver)
1206  {
1207  // Increment XRP balance.
1208  auto const rcvBal = receiver->getFieldAmount(sfBalance);
1209  receiver->setFieldAmount(sfBalance, rcvBal + saAmount);
1210  view.creditHook(xrpAccount(), uReceiverID, saAmount, -rcvBal);
1211 
1212  view.update(receiver);
1213  }
1214 
1215  if (auto stream = j.trace())
1216  {
1217  std::string sender_bal("-");
1218  std::string receiver_bal("-");
1219 
1220  if (sender)
1221  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1222 
1223  if (receiver)
1224  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1225 
1226  stream << "accountSend< " << to_string(uSenderID) << " (" << sender_bal
1227  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1228  << ") : " << saAmount.getFullText();
1229  }
1230 
1231  return terResult;
1232 }
1233 
1234 static bool
1236  ApplyView& view,
1237  SLE::pointer state,
1238  bool bSenderHigh,
1239  AccountID const& sender,
1240  STAmount const& before,
1241  STAmount const& after,
1242  beast::Journal j)
1243 {
1244  if (!state)
1245  return false;
1246  std::uint32_t const flags(state->getFieldU32(sfFlags));
1247 
1248  auto sle = view.peek(keylet::account(sender));
1249  if (!sle)
1250  return false;
1251 
1252  // YYY Could skip this if rippling in reverse.
1253  if (before > beast::zero
1254  // Sender balance was positive.
1255  && after <= beast::zero
1256  // Sender is zero or negative.
1257  && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
1258  // Sender reserve is set.
1259  && static_cast<bool>(
1260  flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
1261  static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
1262  !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
1263  !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
1264  // Sender trust limit is 0.
1265  && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1266  // Sender quality in is 0.
1267  &&
1268  !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1269  // Sender quality out is 0.
1270  {
1271  // VFALCO Where is the line being deleted?
1272  // Clear the reserve of the sender, possibly delete the line!
1273  adjustOwnerCount(view, sle, -1, j);
1274 
1275  // Clear reserve flag.
1276  state->setFieldU32(
1277  sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1278 
1279  // Balance is zero, receiver reserve is clear.
1280  if (!after // Balance is zero.
1281  && !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)))
1282  return true;
1283  }
1284  return false;
1285 }
1286 
1287 TER
1289  ApplyView& view,
1290  AccountID const& account,
1291  STAmount const& amount,
1292  Issue const& issue,
1293  beast::Journal j)
1294 {
1295  assert(!isXRP(account) && !isXRP(issue.account));
1296 
1297  // Consistency check
1298  assert(issue == amount.issue());
1299 
1300  // Can't send to self!
1301  assert(issue.account != account);
1302 
1303  JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": "
1304  << amount.getFullText();
1305 
1306  bool bSenderHigh = issue.account > account;
1307 
1308  auto const index = keylet::line(issue.account, account, issue.currency);
1309 
1310  if (auto state = view.peek(index))
1311  {
1312  STAmount final_balance = state->getFieldAmount(sfBalance);
1313 
1314  if (bSenderHigh)
1315  final_balance.negate(); // Put balance in sender terms.
1316 
1317  STAmount const start_balance = final_balance;
1318 
1319  final_balance -= amount;
1320 
1321  auto const must_delete = updateTrustLine(
1322  view,
1323  state,
1324  bSenderHigh,
1325  issue.account,
1326  start_balance,
1327  final_balance,
1328  j);
1329 
1330  view.creditHook(issue.account, account, amount, start_balance);
1331 
1332  if (bSenderHigh)
1333  final_balance.negate();
1334 
1335  // Adjust the balance on the trust line if necessary. We do this even if
1336  // we are going to delete the line to reflect the correct balance at the
1337  // time of deletion.
1338  state->setFieldAmount(sfBalance, final_balance);
1339  if (must_delete)
1340  return trustDelete(
1341  view,
1342  state,
1343  bSenderHigh ? account : issue.account,
1344  bSenderHigh ? issue.account : account,
1345  j);
1346 
1347  view.update(state);
1348 
1349  return tesSUCCESS;
1350  }
1351 
1352  // NIKB TODO: The limit uses the receiver's account as the issuer and
1353  // this is unnecessarily inefficient as copying which could be avoided
1354  // is now required. Consider available options.
1355  STAmount const limit({issue.currency, account});
1356  STAmount final_balance = amount;
1357 
1358  final_balance.setIssuer(noAccount());
1359 
1360  auto const receiverAccount = view.peek(keylet::account(account));
1361  if (!receiverAccount)
1362  return tefINTERNAL;
1363 
1364  bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
1365 
1366  return trustCreate(
1367  view,
1368  bSenderHigh,
1369  issue.account,
1370  account,
1371  index.key,
1372  receiverAccount,
1373  false,
1374  noRipple,
1375  false,
1376  final_balance,
1377  limit,
1378  0,
1379  0,
1380  j);
1381 }
1382 
1383 TER
1385  ApplyView& view,
1386  AccountID const& account,
1387  STAmount const& amount,
1388  Issue const& issue,
1389  beast::Journal j)
1390 {
1391  assert(!isXRP(account) && !isXRP(issue.account));
1392 
1393  // Consistency check
1394  assert(issue == amount.issue());
1395 
1396  // Can't send to self!
1397  assert(issue.account != account);
1398 
1399  JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": "
1400  << amount.getFullText();
1401 
1402  bool bSenderHigh = account > issue.account;
1403 
1404  if (auto state =
1405  view.peek(keylet::line(account, issue.account, issue.currency)))
1406  {
1407  STAmount final_balance = state->getFieldAmount(sfBalance);
1408 
1409  if (bSenderHigh)
1410  final_balance.negate(); // Put balance in sender terms.
1411 
1412  STAmount const start_balance = final_balance;
1413 
1414  final_balance -= amount;
1415 
1416  auto const must_delete = updateTrustLine(
1417  view, state, bSenderHigh, account, start_balance, final_balance, j);
1418 
1419  view.creditHook(account, issue.account, amount, start_balance);
1420 
1421  if (bSenderHigh)
1422  final_balance.negate();
1423 
1424  // Adjust the balance on the trust line if necessary. We do this even if
1425  // we are going to delete the line to reflect the correct balance at the
1426  // time of deletion.
1427  state->setFieldAmount(sfBalance, final_balance);
1428 
1429  if (must_delete)
1430  {
1431  return trustDelete(
1432  view,
1433  state,
1434  bSenderHigh ? issue.account : account,
1435  bSenderHigh ? account : issue.account,
1436  j);
1437  }
1438 
1439  view.update(state);
1440  return tesSUCCESS;
1441  }
1442 
1443  // In order to hold an IOU, a trust line *MUST* exist to track the
1444  // balance. If it doesn't, then something is very wrong. Don't try
1445  // to continue.
1446  JLOG(j.fatal()) << "redeemIOU: " << to_string(account)
1447  << " attempts to redeem " << amount.getFullText()
1448  << " but no trust line exists!";
1449 
1450  return tefINTERNAL;
1451 }
1452 
1453 TER
1455  ApplyView& view,
1456  AccountID const& from,
1457  AccountID const& to,
1458  STAmount const& amount,
1459  beast::Journal j)
1460 {
1461  assert(from != beast::zero);
1462  assert(to != beast::zero);
1463  assert(from != to);
1464  assert(amount.native());
1465 
1466  SLE::pointer const sender = view.peek(keylet::account(from));
1467  SLE::pointer const receiver = view.peek(keylet::account(to));
1468  if (!sender || !receiver)
1469  return tefINTERNAL;
1470 
1471  JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> "
1472  << to_string(to) << ") : " << amount.getFullText();
1473 
1474  if (sender->getFieldAmount(sfBalance) < amount)
1475  {
1476  // VFALCO Its unfortunate we have to keep
1477  // mutating these TER everywhere
1478  // FIXME: this logic should be moved to callers maybe?
1479  return view.open() ? TER{telFAILED_PROCESSING}
1481  }
1482 
1483  // Decrement XRP balance.
1484  sender->setFieldAmount(
1485  sfBalance, sender->getFieldAmount(sfBalance) - amount);
1486  view.update(sender);
1487 
1488  receiver->setFieldAmount(
1489  sfBalance, receiver->getFieldAmount(sfBalance) + amount);
1490  view.update(receiver);
1491 
1492  return tesSUCCESS;
1493 }
1494 
1495 } // 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:940
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::ApplyView::dirAppend
std::optional< std::uint64_t > dirAppend(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Append an entry to a directory.
Definition: ApplyView.h:277
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::dirAdd
std::optional< std::uint64_t > dirAdd(ApplyView &view, Keylet const &dir, uint256 const &uLedgerIndex, bool strictOrder, std::function< void(SLE::ref)> fDescriber, beast::Journal j)
Definition: View.cpp:725
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:184
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:900
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:1129
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:1085
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:860
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:1454
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:1288
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:740
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:1384
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:38
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:1235
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:314
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