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