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