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.add256(info.parentHash);
48  s.add256(info.txHash);
49  s.add256(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  uint256 const uIndex =
956  getRippleStateIndex(uSenderID, uReceiverID, currency);
957  auto const sleRippleState = view.peek(keylet::line(uIndex));
958 
959  TER terResult;
960 
961  assert(!isXRP(uSenderID) && uSenderID != noAccount());
962  assert(!isXRP(uReceiverID) && uReceiverID != noAccount());
963 
964  if (!sleRippleState)
965  {
966  STAmount const saReceiverLimit({currency, uReceiverID});
967  STAmount saBalance{saAmount};
968 
969  saBalance.setIssuer(noAccount());
970 
971  JLOG(j.debug()) << "rippleCredit: "
972  "create line: "
973  << to_string(uSenderID) << " -> "
974  << to_string(uReceiverID) << " : "
975  << saAmount.getFullText();
976 
977  auto const sleAccount = view.peek(keylet::account(uReceiverID));
978  if (!sleAccount)
979  return tefINTERNAL;
980 
981  bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
982 
983  terResult = trustCreate(
984  view,
985  bSenderHigh,
986  uSenderID,
987  uReceiverID,
988  uIndex,
989  sleAccount,
990  false,
991  noRipple,
992  false,
993  saBalance,
994  saReceiverLimit,
995  0,
996  0,
997  j);
998  }
999  else
1000  {
1001  STAmount saBalance = sleRippleState->getFieldAmount(sfBalance);
1002 
1003  if (bSenderHigh)
1004  saBalance.negate(); // Put balance in sender terms.
1005 
1006  view.creditHook(uSenderID, uReceiverID, saAmount, saBalance);
1007 
1008  STAmount const saBefore = saBalance;
1009 
1010  saBalance -= saAmount;
1011 
1012  JLOG(j.trace()) << "rippleCredit: " << to_string(uSenderID) << " -> "
1013  << to_string(uReceiverID)
1014  << " : before=" << saBefore.getFullText()
1015  << " amount=" << saAmount.getFullText()
1016  << " after=" << saBalance.getFullText();
1017 
1018  std::uint32_t const uFlags(sleRippleState->getFieldU32(sfFlags));
1019  bool bDelete = false;
1020 
1021  // YYY Could skip this if rippling in reverse.
1022  if (saBefore > beast::zero
1023  // Sender balance was positive.
1024  && saBalance <= beast::zero
1025  // Sender is zero or negative.
1026  && (uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
1027  // Sender reserve is set.
1028  &&
1029  static_cast<bool>(
1030  uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
1031  static_cast<bool>(
1032  view.read(keylet::account(uSenderID))->getFlags() &
1033  lsfDefaultRipple) &&
1034  !(uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
1035  !sleRippleState->getFieldAmount(
1036  !bSenderHigh ? sfLowLimit : sfHighLimit)
1037  // Sender trust limit is 0.
1038  && !sleRippleState->getFieldU32(
1039  !bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1040  // Sender quality in is 0.
1041  && !sleRippleState->getFieldU32(
1042  !bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1043  // Sender quality out is 0.
1044  {
1045  // Clear the reserve of the sender, possibly delete the line!
1047  view, view.peek(keylet::account(uSenderID)), -1, j);
1048 
1049  // Clear reserve flag.
1050  sleRippleState->setFieldU32(
1051  sfFlags,
1052  uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1053 
1054  // Balance is zero, receiver reserve is clear.
1055  bDelete = !saBalance // Balance is zero.
1056  && !(uFlags & (bSenderHigh ? lsfLowReserve : lsfHighReserve));
1057  // Receiver reserve is clear.
1058  }
1059 
1060  if (bSenderHigh)
1061  saBalance.negate();
1062 
1063  // Want to reflect balance to zero even if we are deleting line.
1064  sleRippleState->setFieldAmount(sfBalance, saBalance);
1065  // ONLY: Adjust ripple balance.
1066 
1067  if (bDelete)
1068  {
1069  terResult = trustDelete(
1070  view,
1071  sleRippleState,
1072  bSenderHigh ? uReceiverID : uSenderID,
1073  !bSenderHigh ? uReceiverID : uSenderID,
1074  j);
1075  }
1076  else
1077  {
1078  view.update(sleRippleState);
1079  terResult = tesSUCCESS;
1080  }
1081  }
1082 
1083  return terResult;
1084 }
1085 
1086 // Send regardless of limits.
1087 // --> saAmount: Amount/currency/issuer to deliver to receiver.
1088 // <-- saActual: Amount actually cost. Sender pays fees.
1089 static TER
1091  ApplyView& view,
1092  AccountID const& uSenderID,
1093  AccountID const& uReceiverID,
1094  STAmount const& saAmount,
1095  STAmount& saActual,
1096  beast::Journal j)
1097 {
1098  auto const issuer = saAmount.getIssuer();
1099 
1100  assert(!isXRP(uSenderID) && !isXRP(uReceiverID));
1101  assert(uSenderID != uReceiverID);
1102 
1103  if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount())
1104  {
1105  // Direct send: redeeming IOUs and/or sending own IOUs.
1106  auto const ter =
1107  rippleCredit(view, uSenderID, uReceiverID, saAmount, false, j);
1108  if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS)
1109  return ter;
1110  saActual = saAmount;
1111  return tesSUCCESS;
1112  }
1113 
1114  // Sending 3rd party IOUs: transit.
1115 
1116  // Calculate the amount to transfer accounting
1117  // for any transfer fees:
1118  saActual = multiply(saAmount, transferRate(view, issuer));
1119 
1120  JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > "
1121  << to_string(uReceiverID)
1122  << " : deliver=" << saAmount.getFullText()
1123  << " cost=" << saActual.getFullText();
1124 
1125  TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j);
1126 
1127  if (tesSUCCESS == terResult)
1128  terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j);
1129 
1130  return terResult;
1131 }
1132 
1133 TER
1135  ApplyView& view,
1136  AccountID const& uSenderID,
1137  AccountID const& uReceiverID,
1138  STAmount const& saAmount,
1139  beast::Journal j)
1140 {
1141  assert(saAmount >= beast::zero);
1142 
1143  /* If we aren't sending anything or if the sender is the same as the
1144  * receiver then we don't need to do anything.
1145  */
1146  if (!saAmount || (uSenderID == uReceiverID))
1147  return tesSUCCESS;
1148 
1149  if (!saAmount.native())
1150  {
1151  STAmount saActual;
1152 
1153  JLOG(j.trace()) << "accountSend: " << to_string(uSenderID) << " -> "
1154  << to_string(uReceiverID) << " : "
1155  << saAmount.getFullText();
1156 
1157  return rippleSend(view, uSenderID, uReceiverID, saAmount, saActual, j);
1158  }
1159 
1160  /* XRP send which does not check reserve and can do pure adjustment.
1161  * Note that sender or receiver may be null and this not a mistake; this
1162  * setup is used during pathfinding and it is carefully controlled to
1163  * ensure that transfers are balanced.
1164  */
1165  TER terResult(tesSUCCESS);
1166 
1167  SLE::pointer sender = uSenderID != beast::zero
1168  ? view.peek(keylet::account(uSenderID))
1169  : SLE::pointer();
1170  SLE::pointer receiver = uReceiverID != beast::zero
1171  ? view.peek(keylet::account(uReceiverID))
1172  : SLE::pointer();
1173 
1174  if (auto stream = j.trace())
1175  {
1176  std::string sender_bal("-");
1177  std::string receiver_bal("-");
1178 
1179  if (sender)
1180  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1181 
1182  if (receiver)
1183  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1184 
1185  stream << "accountSend> " << to_string(uSenderID) << " (" << sender_bal
1186  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1187  << ") : " << saAmount.getFullText();
1188  }
1189 
1190  if (sender)
1191  {
1192  if (sender->getFieldAmount(sfBalance) < saAmount)
1193  {
1194  // VFALCO Its laborious to have to mutate the
1195  // TER based on params everywhere
1196  terResult = view.open() ? TER{telFAILED_PROCESSING}
1198  }
1199  else
1200  {
1201  auto const sndBal = sender->getFieldAmount(sfBalance);
1202  view.creditHook(uSenderID, xrpAccount(), saAmount, sndBal);
1203 
1204  // Decrement XRP balance.
1205  sender->setFieldAmount(sfBalance, sndBal - saAmount);
1206  view.update(sender);
1207  }
1208  }
1209 
1210  if (tesSUCCESS == terResult && receiver)
1211  {
1212  // Increment XRP balance.
1213  auto const rcvBal = receiver->getFieldAmount(sfBalance);
1214  receiver->setFieldAmount(sfBalance, rcvBal + saAmount);
1215  view.creditHook(xrpAccount(), uReceiverID, saAmount, -rcvBal);
1216 
1217  view.update(receiver);
1218  }
1219 
1220  if (auto stream = j.trace())
1221  {
1222  std::string sender_bal("-");
1223  std::string receiver_bal("-");
1224 
1225  if (sender)
1226  sender_bal = sender->getFieldAmount(sfBalance).getFullText();
1227 
1228  if (receiver)
1229  receiver_bal = receiver->getFieldAmount(sfBalance).getFullText();
1230 
1231  stream << "accountSend< " << to_string(uSenderID) << " (" << sender_bal
1232  << ") -> " << to_string(uReceiverID) << " (" << receiver_bal
1233  << ") : " << saAmount.getFullText();
1234  }
1235 
1236  return terResult;
1237 }
1238 
1239 static bool
1241  ApplyView& view,
1242  SLE::pointer state,
1243  bool bSenderHigh,
1244  AccountID const& sender,
1245  STAmount const& before,
1246  STAmount const& after,
1247  beast::Journal j)
1248 {
1249  if (!state)
1250  return false;
1251  std::uint32_t const flags(state->getFieldU32(sfFlags));
1252 
1253  auto sle = view.peek(keylet::account(sender));
1254  if (!sle)
1255  return false;
1256 
1257  // YYY Could skip this if rippling in reverse.
1258  if (before > beast::zero
1259  // Sender balance was positive.
1260  && after <= beast::zero
1261  // Sender is zero or negative.
1262  && (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
1263  // Sender reserve is set.
1264  && static_cast<bool>(
1265  flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
1266  static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
1267  !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) &&
1268  !state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
1269  // Sender trust limit is 0.
1270  && !state->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
1271  // Sender quality in is 0.
1272  &&
1273  !state->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
1274  // Sender quality out is 0.
1275  {
1276  // VFALCO Where is the line being deleted?
1277  // Clear the reserve of the sender, possibly delete the line!
1278  adjustOwnerCount(view, sle, -1, j);
1279 
1280  // Clear reserve flag.
1281  state->setFieldU32(
1282  sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
1283 
1284  // Balance is zero, receiver reserve is clear.
1285  if (!after // Balance is zero.
1286  && !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)))
1287  return true;
1288  }
1289  return false;
1290 }
1291 
1292 TER
1294  ApplyView& view,
1295  AccountID const& account,
1296  STAmount const& amount,
1297  Issue const& issue,
1298  beast::Journal j)
1299 {
1300  assert(!isXRP(account) && !isXRP(issue.account));
1301 
1302  // Consistency check
1303  assert(issue == amount.issue());
1304 
1305  // Can't send to self!
1306  assert(issue.account != account);
1307 
1308  JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": "
1309  << amount.getFullText();
1310 
1311  bool bSenderHigh = issue.account > account;
1312  uint256 const index =
1313  getRippleStateIndex(issue.account, account, issue.currency);
1314  auto state = view.peek(keylet::line(index));
1315 
1316  if (!state)
1317  {
1318  // NIKB TODO: The limit uses the receiver's account as the issuer and
1319  // this is unnecessarily inefficient as copying which could be avoided
1320  // is now required. Consider available options.
1321  STAmount const limit({issue.currency, account});
1322  STAmount final_balance = amount;
1323 
1324  final_balance.setIssuer(noAccount());
1325 
1326  auto const receiverAccount = view.peek(keylet::account(account));
1327  if (!receiverAccount)
1328  return tefINTERNAL;
1329 
1330  bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
1331 
1332  return trustCreate(
1333  view,
1334  bSenderHigh,
1335  issue.account,
1336  account,
1337  index,
1338  receiverAccount,
1339  false,
1340  noRipple,
1341  false,
1342  final_balance,
1343  limit,
1344  0,
1345  0,
1346  j);
1347  }
1348 
1349  STAmount final_balance = state->getFieldAmount(sfBalance);
1350 
1351  if (bSenderHigh)
1352  final_balance.negate(); // Put balance in sender terms.
1353 
1354  STAmount const start_balance = final_balance;
1355 
1356  final_balance -= amount;
1357 
1358  auto const must_delete = updateTrustLine(
1359  view,
1360  state,
1361  bSenderHigh,
1362  issue.account,
1363  start_balance,
1364  final_balance,
1365  j);
1366 
1367  view.creditHook(issue.account, account, amount, start_balance);
1368 
1369  if (bSenderHigh)
1370  final_balance.negate();
1371 
1372  // Adjust the balance on the trust line if necessary. We do this even if we
1373  // are going to delete the line to reflect the correct balance at the time
1374  // of deletion.
1375  state->setFieldAmount(sfBalance, final_balance);
1376  if (must_delete)
1377  return trustDelete(
1378  view,
1379  state,
1380  bSenderHigh ? account : issue.account,
1381  bSenderHigh ? issue.account : account,
1382  j);
1383 
1384  view.update(state);
1385 
1386  return tesSUCCESS;
1387 }
1388 
1389 TER
1391  ApplyView& view,
1392  AccountID const& account,
1393  STAmount const& amount,
1394  Issue const& issue,
1395  beast::Journal j)
1396 {
1397  assert(!isXRP(account) && !isXRP(issue.account));
1398 
1399  // Consistency check
1400  assert(issue == amount.issue());
1401 
1402  // Can't send to self!
1403  assert(issue.account != account);
1404 
1405  JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": "
1406  << amount.getFullText();
1407 
1408  bool bSenderHigh = account > issue.account;
1409  uint256 const index =
1410  getRippleStateIndex(account, issue.account, issue.currency);
1411  auto state = view.peek(keylet::line(index));
1412 
1413  if (!state)
1414  {
1415  // In order to hold an IOU, a trust line *MUST* exist to track the
1416  // balance. If it doesn't, then something is very wrong. Don't try
1417  // to continue.
1418  JLOG(j.fatal()) << "redeemIOU: " << to_string(account)
1419  << " attempts to redeem " << amount.getFullText()
1420  << " but no trust line exists!";
1421 
1422  return tefINTERNAL;
1423  }
1424 
1425  STAmount final_balance = state->getFieldAmount(sfBalance);
1426 
1427  if (bSenderHigh)
1428  final_balance.negate(); // Put balance in sender terms.
1429 
1430  STAmount const start_balance = final_balance;
1431 
1432  final_balance -= amount;
1433 
1434  auto const must_delete = updateTrustLine(
1435  view, state, bSenderHigh, account, start_balance, final_balance, j);
1436 
1437  view.creditHook(account, issue.account, amount, start_balance);
1438 
1439  if (bSenderHigh)
1440  final_balance.negate();
1441 
1442  // Adjust the balance on the trust line if necessary. We do this even if we
1443  // are going to delete the line to reflect the correct balance at the time
1444  // of deletion.
1445  state->setFieldAmount(sfBalance, final_balance);
1446 
1447  if (must_delete)
1448  {
1449  return trustDelete(
1450  view,
1451  state,
1452  bSenderHigh ? issue.account : account,
1453  bSenderHigh ? account : issue.account,
1454  j);
1455  }
1456 
1457  view.update(state);
1458  return tesSUCCESS;
1459 }
1460 
1461 TER
1463  ApplyView& view,
1464  AccountID const& from,
1465  AccountID const& to,
1466  STAmount const& amount,
1467  beast::Journal j)
1468 {
1469  assert(from != beast::zero);
1470  assert(to != beast::zero);
1471  assert(from != to);
1472  assert(amount.native());
1473 
1474  SLE::pointer const sender = view.peek(keylet::account(from));
1475  SLE::pointer const receiver = view.peek(keylet::account(to));
1476  if (!sender || !receiver)
1477  return tefINTERNAL;
1478 
1479  JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> "
1480  << to_string(to) << ") : " << amount.getFullText();
1481 
1482  if (sender->getFieldAmount(sfBalance) < amount)
1483  {
1484  // VFALCO Its unfortunate we have to keep
1485  // mutating these TER everywhere
1486  // FIXME: this logic should be moved to callers maybe?
1487  return view.open() ? TER{telFAILED_PROCESSING}
1489  }
1490 
1491  // Decrement XRP balance.
1492  sender->setFieldAmount(
1493  sfBalance, sender->getFieldAmount(sfBalance) - amount);
1494  view.update(sender);
1495 
1496  receiver->setFieldAmount(
1497  sfBalance, receiver->getFieldAmount(sfBalance) + amount);
1498  view.update(receiver);
1499 
1500  return tesSUCCESS;
1501 }
1502 
1503 } // 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::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:347
ripple::STAmount::negate
void negate()
Definition: STAmount.h:272
ripple::keylet::skip
static const skip_t skip
Definition: Indexes.h:147
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::Serializer::add8
int add8(unsigned char byte)
Definition: Serializer.cpp:195
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:137
std::string
STL class.
std::shared_ptr
STL class.
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:99
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:147
ripple::STObject::getFieldU64
std::uint64_t getFieldU64(SField const &field) const
Definition: STObject.cpp:549
ripple::STObject::getFieldV256
const STVector256 & getFieldV256(SField const &field) const
Definition: STObject.cpp:601
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: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:495
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: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::sfAccount
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
Definition: SField.h:474
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:516
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::keylet::child
Keylet child(uint256 const &key)
Any item that can be in an owner dir.
Definition: Indexes.cpp:191
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::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:49
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::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:443
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:442
ripple::lsfHighAuth
@ lsfHighAuth
Definition: LedgerFormats.h:150
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:138
ripple::sfOwner
const SF_Account sfOwner(access, STI_ACCOUNT, 2, "Owner")
Definition: SField.h:475
ripple::keylet::line
static const line_t line
Definition: Indexes.h:190
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:426
ripple::majorityAmendments_t
std::map< uint256, NetClock::time_point > majorityAmendments_t
Definition: View.h:158
ripple::STObject::setFieldAmount
void setFieldAmount(SField const &field, STAmount const &)
Definition: STObject.cpp:691
ripple::offerDelete
TER offerDelete(ApplyView &view, std::shared_ptr< SLE > const &sle, beast::Journal j)
Delete an offer.
Definition: View.cpp:896
ripple::keylet::account
static const account_t account
Definition: Indexes.h:120
ripple::STObject::getAccountID
AccountID getAccountID(SField const &field) const
Definition: STObject.cpp:573
ripple::sfAmendment
const SF_U256 sfAmendment(access, STI_HASH256, 19, "Amendment")
Definition: SField.h:429
ripple::TERSubset< CanCvtToTER >
ripple::tecFAILED_PROCESSING
@ tecFAILED_PROCESSING
Definition: TER.h:244
ripple::getRippleStateIndex
uint256 getRippleStateIndex(AccountID const &a, AccountID const &b, Currency const &currency)
Definition: Indexes.cpp:138
ripple::keylet::ownerDir
Keylet ownerDir(AccountID const &id)
The root page of an account's directory.
Definition: Indexes.cpp:296
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:1134
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::rippleSend
static TER rippleSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, STAmount &saActual, beast::Journal j)
Definition: View.cpp:1090
std::map
STL class.
ripple::sfIndexes
const SF_Vec256 sfIndexes(access, STI_VECTOR256, 1, "Indexes", SField::sMD_Never)
Definition: SField.h:487
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:1462
ripple::lsfHighNoRipple
@ lsfHighNoRipple
Definition: LedgerFormats.h:152
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::keylet::amendments
static const amendments_t amendments
Definition: Indexes.h:130
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:573
ripple::sfHashes
const SF_Vec256 sfHashes(access, STI_VECTOR256, 2, "Hashes")
Definition: SField.h:488
ripple::issueIOU
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1293
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::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:438
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:1390
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
std::set::insert
T insert(T... args)
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::Serializer::add64
int add64(std::uint64_t)
Definition: Serializer.cpp:71
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::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:153
ripple::sfAmendments
const SF_Vec256 sfAmendments(access, STI_VECTOR256, 3, "Amendments")
Definition: SField.h:489
std::numeric_limits::max
T max(T... args)
ripple::STObject::getFieldU32
std::uint32_t getFieldU32(SField const &field) const
Definition: STObject.cpp:543
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:1240
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:148
ripple::STObject::setFieldU32
void setFieldU32(SField const &field, std::uint32_t)
Definition: STObject.cpp:643
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:587
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::keylet::page
Keylet page(uint256 const &key, std::uint64_t index)
A page in a directory.
Definition: Indexes.cpp:302
ripple::Serializer::add256
int add256(uint256 const &)
Definition: Serializer.cpp:119
ripple::LedgerInfo::parentCloseTime
NetClock::time_point parentCloseTime
Definition: ReadView.h:89
ripple::STObject::getFieldH256
uint256 getFieldH256(SField const &field) const
Definition: STObject.cpp:567
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