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