rippled
STAmount.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/contract.h>
22 #include <ripple/basics/safe_cast.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/protocol/STAmount.h>
25 #include <ripple/protocol/SystemParameters.h>
26 #include <ripple/protocol/UintTypes.h>
27 #include <ripple/protocol/jss.h>
28 #include <boost/algorithm/string.hpp>
29 #include <boost/multiprecision/cpp_int.hpp>
30 #include <boost/regex.hpp>
31 #include <iostream>
32 #include <iterator>
33 #include <memory>
34 
35 namespace ripple {
36 
37 LocalValue<bool> stAmountCanonicalizeSwitchover(true);
38 
39 static const std::uint64_t tenTo14 = 100000000000000ull;
40 static const std::uint64_t tenTo14m1 = tenTo14 - 1;
41 static const std::uint64_t tenTo17 = tenTo14 * 1000;
42 
43 //------------------------------------------------------------------------------
44 static std::int64_t
45 getSNValue(STAmount const& amount)
46 {
47  if (!amount.native())
48  Throw<std::runtime_error>("amount is not native!");
49 
50  auto ret = static_cast<std::int64_t>(amount.mantissa());
51 
52  assert(static_cast<std::uint64_t>(ret) == amount.mantissa());
53 
54  if (amount.negative())
55  ret = -ret;
56 
57  return ret;
58 }
59 
60 static bool
61 areComparable(STAmount const& v1, STAmount const& v2)
62 {
63  return v1.native() == v2.native() &&
64  v1.issue().currency == v2.issue().currency;
65 }
66 
67 STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name)
68 {
69  std::uint64_t value = sit.get64();
70 
71  // native
72  if ((value & cNotNative) == 0)
73  {
74  // positive
75  if ((value & cPosNative) != 0)
76  {
77  mValue = value & ~cPosNative;
78  mOffset = 0;
79  mIsNative = true;
80  mIsNegative = false;
81  return;
82  }
83 
84  // negative
85  if (value == 0)
86  Throw<std::runtime_error>("negative zero is not canonical");
87 
88  mValue = value;
89  mOffset = 0;
90  mIsNative = true;
91  mIsNegative = true;
92  return;
93  }
94 
95  Issue issue;
96  issue.currency = sit.get160();
97 
98  if (isXRP(issue.currency))
99  Throw<std::runtime_error>("invalid native currency");
100 
101  issue.account = sit.get160();
102 
103  if (isXRP(issue.account))
104  Throw<std::runtime_error>("invalid native account");
105 
106  // 10 bits for the offset, sign and "not native" flag
107  int offset = static_cast<int>(value >> (64 - 10));
108 
109  value &= ~(1023ull << (64 - 10));
110 
111  if (value)
112  {
113  bool isNegative = (offset & 256) == 0;
114  offset = (offset & 255) - 97; // center the range
115 
116  if (value < cMinValue || value > cMaxValue || offset < cMinOffset ||
117  offset > cMaxOffset)
118  {
119  Throw<std::runtime_error>("invalid currency value");
120  }
121 
122  mIssue = issue;
123  mValue = value;
124  mOffset = offset;
125  mIsNegative = isNegative;
126  canonicalize();
127  return;
128  }
129 
130  if (offset != 512)
131  Throw<std::runtime_error>("invalid currency value");
132 
133  mIssue = issue;
134  mValue = 0;
135  mOffset = 0;
136  mIsNegative = false;
137  canonicalize();
138 }
139 
141  SField const& name,
142  Issue const& issue,
143  mantissa_type mantissa,
144  exponent_type exponent,
145  bool native,
146  bool negative,
147  unchecked)
148  : STBase(name)
149  , mIssue(issue)
150  , mValue(mantissa)
151  , mOffset(exponent)
152  , mIsNative(native)
153  , mIsNegative(negative)
154 {
155 }
156 
158  Issue const& issue,
159  mantissa_type mantissa,
160  exponent_type exponent,
161  bool native,
162  bool negative,
163  unchecked)
164  : mIssue(issue)
165  , mValue(mantissa)
166  , mOffset(exponent)
167  , mIsNative(native)
168  , mIsNegative(negative)
169 {
170 }
171 
173  SField const& name,
174  Issue const& issue,
175  mantissa_type mantissa,
176  exponent_type exponent,
177  bool native,
178  bool negative)
179  : STBase(name)
180  , mIssue(issue)
181  , mValue(mantissa)
182  , mOffset(exponent)
183  , mIsNative(native)
184  , mIsNegative(negative)
185 {
186  canonicalize();
187 }
188 
189 STAmount::STAmount(SField const& name, std::int64_t mantissa)
190  : STBase(name), mOffset(0), mIsNative(true)
191 {
192  set(mantissa);
193 }
194 
195 STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative)
196  : STBase(name)
197  , mValue(mantissa)
198  , mOffset(0)
199  , mIsNative(true)
200  , mIsNegative(negative)
201 {
203 }
204 
206  SField const& name,
207  Issue const& issue,
208  std::uint64_t mantissa,
209  int exponent,
210  bool negative)
211  : STBase(name)
212  , mIssue(issue)
213  , mValue(mantissa)
214  , mOffset(exponent)
215  , mIsNegative(negative)
216 {
218  canonicalize();
219 }
220 
221 //------------------------------------------------------------------------------
222 
223 STAmount::STAmount(std::uint64_t mantissa, bool negative)
224  : mValue(mantissa)
225  , mOffset(0)
226  , mIsNative(true)
227  , mIsNegative(mantissa != 0 && negative)
228 {
230 }
231 
233  Issue const& issue,
234  std::uint64_t mantissa,
235  int exponent,
236  bool negative)
237  : mIssue(issue), mValue(mantissa), mOffset(exponent), mIsNegative(negative)
238 {
239  canonicalize();
240 }
241 
242 STAmount::STAmount(Issue const& issue, std::int64_t mantissa, int exponent)
243  : mIssue(issue), mOffset(exponent)
244 {
245  set(mantissa);
246  canonicalize();
247 }
248 
250  Issue const& issue,
251  std::uint32_t mantissa,
252  int exponent,
253  bool negative)
254  : STAmount(issue, safe_cast<std::uint64_t>(mantissa), exponent, negative)
255 {
256 }
257 
258 STAmount::STAmount(Issue const& issue, int mantissa, int exponent)
259  : STAmount(issue, safe_cast<std::int64_t>(mantissa), exponent)
260 {
261 }
262 
263 // Legacy support for new-style amounts
264 STAmount::STAmount(IOUAmount const& amount, Issue const& issue)
265  : mIssue(issue)
266  , mOffset(amount.exponent())
267  , mIsNative(false)
268  , mIsNegative(amount < beast::zero)
269 {
270  if (mIsNegative)
271  mValue = static_cast<std::uint64_t>(-amount.mantissa());
272  else
273  mValue = static_cast<std::uint64_t>(amount.mantissa());
274 
275  canonicalize();
276 }
277 
279  : mOffset(0), mIsNative(true), mIsNegative(amount < beast::zero)
280 {
281  if (mIsNegative)
282  mValue = unsafe_cast<std::uint64_t>(-amount.drops());
283  else
284  mValue = unsafe_cast<std::uint64_t>(amount.drops());
285 
286  canonicalize();
287 }
288 
291 {
292  return std::make_unique<STAmount>(sit, name);
293 }
294 
295 STBase*
296 STAmount::copy(std::size_t n, void* buf) const
297 {
298  return emplace(n, buf, *this);
299 }
300 
301 STBase*
303 {
304  return emplace(n, buf, std::move(*this));
305 }
306 
307 //------------------------------------------------------------------------------
308 //
309 // Conversion
310 //
311 //------------------------------------------------------------------------------
312 XRPAmount
314 {
315  if (!mIsNative)
316  Throw<std::logic_error>(
317  "Cannot return non-native STAmount as XRPAmount");
318 
319  auto drops = static_cast<XRPAmount::value_type>(mValue);
320 
321  if (mIsNegative)
322  drops = -drops;
323 
324  return XRPAmount{drops};
325 }
326 
327 IOUAmount
329 {
330  if (mIsNative)
331  Throw<std::logic_error>("Cannot return native STAmount as IOUAmount");
332 
333  auto mantissa = static_cast<std::int64_t>(mValue);
334  auto exponent = mOffset;
335 
336  if (mIsNegative)
337  mantissa = -mantissa;
338 
339  return {mantissa, exponent};
340 }
341 
342 STAmount&
344 {
345  assert(mIsNative == false);
346  mOffset = iou.exponent();
347  mIsNegative = iou < beast::zero;
348  if (mIsNegative)
349  mValue = static_cast<std::uint64_t>(-iou.mantissa());
350  else
351  mValue = static_cast<std::uint64_t>(iou.mantissa());
352  return *this;
353 }
354 
355 //------------------------------------------------------------------------------
356 //
357 // Operators
358 //
359 //------------------------------------------------------------------------------
360 
361 STAmount&
363 {
364  *this = *this + a;
365  return *this;
366 }
367 
368 STAmount&
370 {
371  *this = *this - a;
372  return *this;
373 }
374 
375 STAmount
376 operator+(STAmount const& v1, STAmount const& v2)
377 {
378  if (!areComparable(v1, v2))
379  Throw<std::runtime_error>("Can't add amounts that are't comparable!");
380 
381  if (v2 == beast::zero)
382  return v1;
383 
384  if (v1 == beast::zero)
385  {
386  // Result must be in terms of v1 currency and issuer.
387  return {
388  v1.getFName(),
389  v1.issue(),
390  v2.mantissa(),
391  v2.exponent(),
392  v2.negative()};
393  }
394 
395  if (v1.native())
396  return {v1.getFName(), getSNValue(v1) + getSNValue(v2)};
397 
398  if (*stNumberSwitchover)
399  {
400  auto x = v1;
401  x = v1.iou() + v2.iou();
402  return x;
403  }
404 
405  int ov1 = v1.exponent(), ov2 = v2.exponent();
406  std::int64_t vv1 = static_cast<std::int64_t>(v1.mantissa());
407  std::int64_t vv2 = static_cast<std::int64_t>(v2.mantissa());
408 
409  if (v1.negative())
410  vv1 = -vv1;
411 
412  if (v2.negative())
413  vv2 = -vv2;
414 
415  while (ov1 < ov2)
416  {
417  vv1 /= 10;
418  ++ov1;
419  }
420 
421  while (ov2 < ov1)
422  {
423  vv2 /= 10;
424  ++ov2;
425  }
426 
427  // This addition cannot overflow an std::int64_t. It can overflow an
428  // STAmount and the constructor will throw.
429 
430  std::int64_t fv = vv1 + vv2;
431 
432  if ((fv >= -10) && (fv <= 10))
433  return {v1.getFName(), v1.issue()};
434 
435  if (fv >= 0)
436  return STAmount{
437  v1.getFName(),
438  v1.issue(),
439  static_cast<std::uint64_t>(fv),
440  ov1,
441  false};
442 
443  return STAmount{
444  v1.getFName(), v1.issue(), static_cast<std::uint64_t>(-fv), ov1, true};
445 }
446 
447 STAmount
448 operator-(STAmount const& v1, STAmount const& v2)
449 {
450  return v1 + (-v2);
451 }
452 
453 //------------------------------------------------------------------------------
454 
455 std::uint64_t const STAmount::uRateOne = getRate(STAmount(1), STAmount(1));
456 
457 void
459 {
460  mIssue = issue;
461  mIsNative = isXRP(*this);
462 }
463 
464 // Convert an offer into an index amount so they sort by rate.
465 // A taker will take the best, lowest, rate first.
466 // (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2.
467 // --> offerOut: takerGets: How much the offerer is selling to the taker.
468 // --> offerIn: takerPays: How much the offerer is receiving from the taker.
469 // <-- uRate: normalize(offerIn/offerOut)
470 // A lower rate is better for the person taking the order.
471 // The taker gets more for less with a lower rate.
472 // Zero is returned if the offer is worthless.
474 getRate(STAmount const& offerOut, STAmount const& offerIn)
475 {
476  if (offerOut == beast::zero)
477  return 0;
478  try
479  {
480  STAmount r = divide(offerIn, offerOut, noIssue());
481  if (r == beast::zero) // offer is too good
482  return 0;
483  assert((r.exponent() >= -100) && (r.exponent() <= 155));
484  std::uint64_t ret = r.exponent() + 100;
485  return (ret << (64 - 8)) | r.mantissa();
486  }
487  catch (std::exception const&)
488  {
489  }
490 
491  // overflow -- very bad offer
492  return 0;
493 }
494 
495 void
497 {
498  elem = Json::objectValue;
499 
500  if (!mIsNative)
501  {
502  // It is an error for currency or issuer not to be specified for valid
503  // json.
504  elem[jss::value] = getText();
505  elem[jss::currency] = to_string(mIssue.currency);
506  elem[jss::issuer] = to_string(mIssue.account);
507  }
508  else
509  {
510  elem = getText();
511  }
512 }
513 
514 //------------------------------------------------------------------------------
515 //
516 // STBase
517 //
518 //------------------------------------------------------------------------------
519 
522 {
523  return STI_AMOUNT;
524 }
525 
528 {
529  std::string ret;
530 
531  ret.reserve(64);
532  ret = getText() + "/" + to_string(mIssue.currency);
533 
534  if (!mIsNative)
535  {
536  ret += "/";
537 
538  if (isXRP(*this))
539  ret += "0";
540  else if (mIssue.account == noAccount())
541  ret += "1";
542  else
543  ret += to_string(mIssue.account);
544  }
545 
546  return ret;
547 }
548 
551 {
552  // keep full internal accuracy, but make more human friendly if posible
553  if (*this == beast::zero)
554  return "0";
555 
556  std::string const raw_value(std::to_string(mValue));
557  std::string ret;
558 
559  if (mIsNegative)
560  ret.append(1, '-');
561 
562  bool const scientific(
563  (mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
564 
565  if (mIsNative || scientific)
566  {
567  ret.append(raw_value);
568 
569  if (scientific)
570  {
571  ret.append(1, 'e');
573  }
574 
575  return ret;
576  }
577 
578  assert(mOffset + 43 > 0);
579 
580  size_t const pad_prefix = 27;
581  size_t const pad_suffix = 23;
582 
583  std::string val;
584  val.reserve(raw_value.length() + pad_prefix + pad_suffix);
585  val.append(pad_prefix, '0');
586  val.append(raw_value);
587  val.append(pad_suffix, '0');
588 
589  size_t const offset(mOffset + 43);
590 
591  auto pre_from(val.begin());
592  auto const pre_to(val.begin() + offset);
593 
594  auto const post_from(val.begin() + offset);
595  auto post_to(val.end());
596 
597  // Crop leading zeroes. Take advantage of the fact that there's always a
598  // fixed amount of leading zeroes and skip them.
599  if (std::distance(pre_from, pre_to) > pad_prefix)
600  pre_from += pad_prefix;
601 
602  assert(post_to >= post_from);
603 
604  pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
605 
606  // Crop trailing zeroes. Take advantage of the fact that there's always a
607  // fixed amount of trailing zeroes and skip them.
608  if (std::distance(post_from, post_to) > pad_suffix)
609  post_to -= pad_suffix;
610 
611  assert(post_to >= post_from);
612 
613  post_to = std::find_if(
615  std::make_reverse_iterator(post_from),
616  [](char c) { return c != '0'; })
617  .base();
618 
619  // Assemble the output:
620  if (pre_from == pre_to)
621  ret.append(1, '0');
622  else
623  ret.append(pre_from, pre_to);
624 
625  if (post_to != post_from)
626  {
627  ret.append(1, '.');
628  ret.append(post_from, post_to);
629  }
630 
631  return ret;
632 }
633 
635 {
636  Json::Value elem;
637  setJson(elem);
638  return elem;
639 }
640 
641 void
643 {
644  if (mIsNative)
645  {
646  assert(mOffset == 0);
647 
648  if (!mIsNegative)
649  s.add64(mValue | cPosNative);
650  else
651  s.add64(mValue);
652  }
653  else
654  {
655  if (*this == beast::zero)
656  s.add64(cNotNative);
657  else if (mIsNegative) // 512 = not native
658  s.add64(
659  mValue |
660  (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
661  else // 256 = positive
662  s.add64(
663  mValue |
664  (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
665  << (64 - 10)));
666 
669  }
670 }
671 
672 bool
674 {
675  const STAmount* v = dynamic_cast<const STAmount*>(&t);
676  return v && (*v == *this);
677 }
678 
679 bool
681 {
682  return (mValue == 0) && mIsNative;
683 }
684 
685 //------------------------------------------------------------------------------
686 
687 // amount = mValue * [10 ^ mOffset]
688 // Representation range is 10^80 - 10^(-80).
689 //
690 // On the wire:
691 // - high bit is 0 for XRP, 1 for issued currency
692 // - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
693 // is a special case of 0x8000000000000000
694 // - for issued currencies, the next 8 bits are (mOffset+97).
695 // The +97 is so that this value is always positive.
696 // - The remaining bits are significant digits (mantissa)
697 // That's 54 bits for issued currency and 62 bits for native
698 // (but XRP only needs 57 bits for the max value of 10^17 drops)
699 //
700 // mValue is zero if the amount is zero, otherwise it's within the range
701 // 10^15 to (10^16 - 1) inclusive.
702 // mOffset is in the range -96 to +80.
703 void
705 {
706  if (isXRP(*this))
707  {
708  // native currency amounts should always have an offset of zero
709  mIsNative = true;
710 
711  // log(2^64,10) ~ 19.2
712  if (mValue == 0 || mOffset <= -20)
713  {
714  mValue = 0;
715  mOffset = 0;
716  mIsNegative = false;
717  return;
718  }
719 
721  {
722  // log(cMaxNativeN, 10) == 17
723  if (mOffset > 17)
724  Throw<std::runtime_error>(
725  "Native currency amount out of range");
726  }
727 
729  {
730  Number num(
732  XRPAmount xrp{num};
733  mIsNegative = xrp.drops() < 0;
734  mValue = mIsNegative ? -xrp.drops() : xrp.drops();
735  mOffset = 0;
736  }
737  else
738  {
739  while (mOffset < 0)
740  {
741  mValue /= 10;
742  ++mOffset;
743  }
744 
745  while (mOffset > 0)
746  {
748  {
749  // N.B. do not move the overflow check to after the
750  // multiplication
751  if (mValue > cMaxNativeN)
752  Throw<std::runtime_error>(
753  "Native currency amount out of range");
754  }
755  mValue *= 10;
756  --mOffset;
757  }
758  }
759 
760  if (mValue > cMaxNativeN)
761  Throw<std::runtime_error>("Native currency amount out of range");
762 
763  return;
764  }
765 
766  mIsNative = false;
767 
768  if (*stNumberSwitchover)
769  {
770  *this = iou();
771  return;
772  }
773 
774  if (mValue == 0)
775  {
776  mOffset = -100;
777  mIsNegative = false;
778  return;
779  }
780 
781  while ((mValue < cMinValue) && (mOffset > cMinOffset))
782  {
783  mValue *= 10;
784  --mOffset;
785  }
786 
787  while (mValue > cMaxValue)
788  {
789  if (mOffset >= cMaxOffset)
790  Throw<std::runtime_error>("value overflow");
791 
792  mValue /= 10;
793  ++mOffset;
794  }
795 
796  if ((mOffset < cMinOffset) || (mValue < cMinValue))
797  {
798  mValue = 0;
799  mIsNegative = false;
800  mOffset = -100;
801  return;
802  }
803 
804  if (mOffset > cMaxOffset)
805  Throw<std::runtime_error>("value overflow");
806 
807  assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)));
808  assert(
809  (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)));
810  assert((mValue != 0) || (mOffset != -100));
811 }
812 
813 void
815 {
816  if (v < 0)
817  {
818  mIsNegative = true;
819  mValue = static_cast<std::uint64_t>(-v);
820  }
821  else
822  {
823  mIsNegative = false;
824  mValue = static_cast<std::uint64_t>(v);
825  }
826 }
827 
828 //------------------------------------------------------------------------------
829 
830 STAmount
832 {
833  if (rate == 0)
834  return STAmount(noIssue());
835 
836  std::uint64_t mantissa = rate & ~(255ull << (64 - 8));
837  int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
838 
839  return STAmount(noIssue(), mantissa, exponent);
840 }
841 
842 STAmount
843 amountFromString(Issue const& issue, std::string const& amount)
844 {
845  static boost::regex const reNumber(
846  "^" // the beginning of the string
847  "([-+]?)" // (optional) + or - character
848  "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
849  "(\\.([0-9]+))?" // (optional) period followed by any number
850  "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
851  "$",
852  boost::regex_constants::optimize);
853 
854  boost::smatch match;
855 
856  if (!boost::regex_match(amount, match, reNumber))
857  Throw<std::runtime_error>("Number '" + amount + "' is not valid");
858 
859  // Match fields:
860  // 0 = whole input
861  // 1 = sign
862  // 2 = integer portion
863  // 3 = whole fraction (with '.')
864  // 4 = fraction (without '.')
865  // 5 = whole exponent (with 'e')
866  // 6 = exponent sign
867  // 7 = exponent number
868 
869  // CHECKME: Why 32? Shouldn't this be 16?
870  if ((match[2].length() + match[4].length()) > 32)
871  Throw<std::runtime_error>("Number '" + amount + "' is overlong");
872 
873  bool negative = (match[1].matched && (match[1] == "-"));
874 
875  // Can't specify XRP using fractional representation
876  if (isXRP(issue) && match[3].matched)
877  Throw<std::runtime_error>("XRP must be specified in integral drops.");
878 
879  std::uint64_t mantissa;
880  int exponent;
881 
882  if (!match[4].matched) // integer only
883  {
884  mantissa =
885  beast::lexicalCastThrow<std::uint64_t>(std::string(match[2]));
886  exponent = 0;
887  }
888  else
889  {
890  // integer and fraction
891  mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
892  exponent = -(match[4].length());
893  }
894 
895  if (match[5].matched)
896  {
897  // we have an exponent
898  if (match[6].matched && (match[6] == "-"))
899  exponent -= beast::lexicalCastThrow<int>(std::string(match[7]));
900  else
901  exponent += beast::lexicalCastThrow<int>(std::string(match[7]));
902  }
903 
904  return {issue, mantissa, exponent, negative};
905 }
906 
907 STAmount
908 amountFromJson(SField const& name, Json::Value const& v)
909 {
910  STAmount::mantissa_type mantissa = 0;
911  STAmount::exponent_type exponent = 0;
912  bool negative = false;
913  Issue issue;
914 
915  Json::Value value;
916  Json::Value currency;
917  Json::Value issuer;
918 
919  if (v.isNull())
920  {
921  Throw<std::runtime_error>(
922  "XRP may not be specified with a null Json value");
923  }
924  else if (v.isObject())
925  {
926  value = v[jss::value];
927  currency = v[jss::currency];
928  issuer = v[jss::issuer];
929  }
930  else if (v.isArray())
931  {
932  value = v.get(Json::UInt(0), 0);
933  currency = v.get(Json::UInt(1), Json::nullValue);
934  issuer = v.get(Json::UInt(2), Json::nullValue);
935  }
936  else if (v.isString())
937  {
938  std::string val = v.asString();
939  std::vector<std::string> elements;
940  boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
941 
942  if (elements.size() > 3)
943  Throw<std::runtime_error>("invalid amount string");
944 
945  value = elements[0];
946 
947  if (elements.size() > 1)
948  currency = elements[1];
949 
950  if (elements.size() > 2)
951  issuer = elements[2];
952  }
953  else
954  {
955  value = v;
956  }
957 
958  bool const native = !currency.isString() || currency.asString().empty() ||
959  (currency.asString() == systemCurrencyCode());
960 
961  if (native)
962  {
963  if (v.isObjectOrNull())
964  Throw<std::runtime_error>("XRP may not be specified as an object");
965  issue = xrpIssue();
966  }
967  else
968  {
969  // non-XRP
970  if (!to_currency(issue.currency, currency.asString()))
971  Throw<std::runtime_error>("invalid currency");
972 
973  if (!issuer.isString() || !to_issuer(issue.account, issuer.asString()))
974  Throw<std::runtime_error>("invalid issuer");
975 
976  if (isXRP(issue.currency))
977  Throw<std::runtime_error>("invalid issuer");
978  }
979 
980  if (value.isInt())
981  {
982  if (value.asInt() >= 0)
983  {
984  mantissa = value.asInt();
985  }
986  else
987  {
988  mantissa = -value.asInt();
989  negative = true;
990  }
991  }
992  else if (value.isUInt())
993  {
994  mantissa = v.asUInt();
995  }
996  else if (value.isString())
997  {
998  auto const ret = amountFromString(issue, value.asString());
999 
1000  mantissa = ret.mantissa();
1001  exponent = ret.exponent();
1002  negative = ret.negative();
1003  }
1004  else
1005  {
1006  Throw<std::runtime_error>("invalid amount type");
1007  }
1008 
1009  return {name, issue, mantissa, exponent, native, negative};
1010 }
1011 
1012 bool
1013 amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource)
1014 {
1015  try
1016  {
1017  result = amountFromJson(sfGeneric, jvSource);
1018  return true;
1019  }
1020  catch (const std::exception& e)
1021  {
1022  JLOG(debugLog().warn())
1023  << "amountFromJsonNoThrow: caught: " << e.what();
1024  }
1025  return false;
1026 }
1027 
1028 //------------------------------------------------------------------------------
1029 //
1030 // Operators
1031 //
1032 //------------------------------------------------------------------------------
1033 
1034 bool
1035 operator==(STAmount const& lhs, STAmount const& rhs)
1036 {
1037  return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() &&
1038  lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa();
1039 }
1040 
1041 bool
1042 operator<(STAmount const& lhs, STAmount const& rhs)
1043 {
1044  if (!areComparable(lhs, rhs))
1045  Throw<std::runtime_error>(
1046  "Can't compare amounts that are't comparable!");
1047 
1048  if (lhs.negative() != rhs.negative())
1049  return lhs.negative();
1050 
1051  if (lhs.mantissa() == 0)
1052  {
1053  if (rhs.negative())
1054  return false;
1055  return rhs.mantissa() != 0;
1056  }
1057 
1058  // We know that lhs is non-zero and both sides have the same sign. Since
1059  // rhs is zero (and thus not negative), lhs must, therefore, be strictly
1060  // greater than zero. So if rhs is zero, the comparison must be false.
1061  if (rhs.mantissa() == 0)
1062  return false;
1063 
1064  if (lhs.exponent() > rhs.exponent())
1065  return lhs.negative();
1066  if (lhs.exponent() < rhs.exponent())
1067  return !lhs.negative();
1068  if (lhs.mantissa() > rhs.mantissa())
1069  return lhs.negative();
1070  if (lhs.mantissa() < rhs.mantissa())
1071  return !lhs.negative();
1072 
1073  return false;
1074 }
1075 
1076 STAmount
1077 operator-(STAmount const& value)
1078 {
1079  if (value.mantissa() == 0)
1080  return value;
1081  return STAmount(
1082  value.getFName(),
1083  value.issue(),
1084  value.mantissa(),
1085  value.exponent(),
1086  value.native(),
1087  !value.negative(),
1089 }
1090 
1091 //------------------------------------------------------------------------------
1092 //
1093 // Arithmetic
1094 //
1095 //------------------------------------------------------------------------------
1096 
1097 // Calculate (a * b) / c when all three values are 64-bit
1098 // without loss of precision:
1099 static std::uint64_t
1101  std::uint64_t multiplier,
1102  std::uint64_t multiplicand,
1103  std::uint64_t divisor)
1104 {
1105  boost::multiprecision::uint128_t ret;
1106 
1107  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1108  ret /= divisor;
1109 
1111  {
1112  Throw<std::overflow_error>(
1113  "overflow: (" + std::to_string(multiplier) + " * " +
1114  std::to_string(multiplicand) + ") / " + std::to_string(divisor));
1115  }
1116 
1117  return static_cast<uint64_t>(ret);
1118 }
1119 
1120 static std::uint64_t
1122  std::uint64_t multiplier,
1123  std::uint64_t multiplicand,
1124  std::uint64_t divisor,
1125  std::uint64_t rounding)
1126 {
1127  boost::multiprecision::uint128_t ret;
1128 
1129  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1130  ret += rounding;
1131  ret /= divisor;
1132 
1134  {
1135  Throw<std::overflow_error>(
1136  "overflow: ((" + std::to_string(multiplier) + " * " +
1137  std::to_string(multiplicand) + ") + " + std::to_string(rounding) +
1138  ") / " + std::to_string(divisor));
1139  }
1140 
1141  return static_cast<uint64_t>(ret);
1142 }
1143 
1144 STAmount
1145 divide(STAmount const& num, STAmount const& den, Issue const& issue)
1146 {
1147  if (den == beast::zero)
1148  Throw<std::runtime_error>("division by zero");
1149 
1150  if (num == beast::zero)
1151  return {issue};
1152 
1153  std::uint64_t numVal = num.mantissa();
1154  std::uint64_t denVal = den.mantissa();
1155  int numOffset = num.exponent();
1156  int denOffset = den.exponent();
1157 
1158  if (num.native())
1159  {
1160  while (numVal < STAmount::cMinValue)
1161  {
1162  // Need to bring into range
1163  numVal *= 10;
1164  --numOffset;
1165  }
1166  }
1167 
1168  if (den.native())
1169  {
1170  while (denVal < STAmount::cMinValue)
1171  {
1172  denVal *= 10;
1173  --denOffset;
1174  }
1175  }
1176 
1177  // We divide the two mantissas (each is between 10^15
1178  // and 10^16). To maintain precision, we multiply the
1179  // numerator by 10^17 (the product is in the range of
1180  // 10^32 to 10^33) followed by a division, so the result
1181  // is in the range of 10^16 to 10^15.
1182  return STAmount(
1183  issue,
1184  muldiv(numVal, tenTo17, denVal) + 5,
1185  numOffset - denOffset - 17,
1186  num.negative() != den.negative());
1187 }
1188 
1189 STAmount
1190 multiply(STAmount const& v1, STAmount const& v2, Issue const& issue)
1191 {
1192  if (v1 == beast::zero || v2 == beast::zero)
1193  return STAmount(issue);
1194 
1195  if (v1.native() && v2.native() && isXRP(issue))
1196  {
1197  std::uint64_t const minV =
1198  getSNValue(v1) < getSNValue(v2) ? getSNValue(v1) : getSNValue(v2);
1199  std::uint64_t const maxV =
1200  getSNValue(v1) < getSNValue(v2) ? getSNValue(v2) : getSNValue(v1);
1201 
1202  if (minV > 3000000000ull) // sqrt(cMaxNative)
1203  Throw<std::runtime_error>("Native value overflow");
1204 
1205  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1206  Throw<std::runtime_error>("Native value overflow");
1207 
1208  return STAmount(v1.getFName(), minV * maxV);
1209  }
1210 
1211  if (*stNumberSwitchover)
1212  return {IOUAmount{Number{v1} * Number{v2}}, issue};
1213 
1214  std::uint64_t value1 = v1.mantissa();
1215  std::uint64_t value2 = v2.mantissa();
1216  int offset1 = v1.exponent();
1217  int offset2 = v2.exponent();
1218 
1219  if (v1.native())
1220  {
1221  while (value1 < STAmount::cMinValue)
1222  {
1223  value1 *= 10;
1224  --offset1;
1225  }
1226  }
1227 
1228  if (v2.native())
1229  {
1230  while (value2 < STAmount::cMinValue)
1231  {
1232  value2 *= 10;
1233  --offset2;
1234  }
1235  }
1236 
1237  // We multiply the two mantissas (each is between 10^15
1238  // and 10^16), so their product is in the 10^30 to 10^32
1239  // range. Dividing their product by 10^14 maintains the
1240  // precision, by scaling the result to 10^16 to 10^18.
1241  return STAmount(
1242  issue,
1243  muldiv(value1, value2, tenTo14) + 7,
1244  offset1 + offset2 + 14,
1245  v1.negative() != v2.negative());
1246 }
1247 
1248 static void
1249 canonicalizeRound(bool native, std::uint64_t& value, int& offset)
1250 {
1251  if (native)
1252  {
1253  if (offset < 0)
1254  {
1255  int loops = 0;
1256 
1257  while (offset < -1)
1258  {
1259  value /= 10;
1260  ++offset;
1261  ++loops;
1262  }
1263 
1264  value += (loops >= 2) ? 9 : 10; // add before last divide
1265  value /= 10;
1266  ++offset;
1267  }
1268  }
1269  else if (value > STAmount::cMaxValue)
1270  {
1271  while (value > (10 * STAmount::cMaxValue))
1272  {
1273  value /= 10;
1274  ++offset;
1275  }
1276 
1277  value += 9; // add before last divide
1278  value /= 10;
1279  ++offset;
1280  }
1281 }
1282 
1283 STAmount
1285  STAmount const& v1,
1286  STAmount const& v2,
1287  Issue const& issue,
1288  bool roundUp)
1289 {
1290  if (v1 == beast::zero || v2 == beast::zero)
1291  return {issue};
1292 
1293  bool const xrp = isXRP(issue);
1294 
1295  if (v1.native() && v2.native() && xrp)
1296  {
1297  std::uint64_t minV =
1298  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v1) : getSNValue(v2);
1299  std::uint64_t maxV =
1300  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v2) : getSNValue(v1);
1301 
1302  if (minV > 3000000000ull) // sqrt(cMaxNative)
1303  Throw<std::runtime_error>("Native value overflow");
1304 
1305  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1306  Throw<std::runtime_error>("Native value overflow");
1307 
1308  return STAmount(v1.getFName(), minV * maxV);
1309  }
1310 
1311  std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1312  int offset1 = v1.exponent(), offset2 = v2.exponent();
1313 
1314  if (v1.native())
1315  {
1316  while (value1 < STAmount::cMinValue)
1317  {
1318  value1 *= 10;
1319  --offset1;
1320  }
1321  }
1322 
1323  if (v2.native())
1324  {
1325  while (value2 < STAmount::cMinValue)
1326  {
1327  value2 *= 10;
1328  --offset2;
1329  }
1330  }
1331 
1332  bool const resultNegative = v1.negative() != v2.negative();
1333 
1334  // We multiply the two mantissas (each is between 10^15
1335  // and 10^16), so their product is in the 10^30 to 10^32
1336  // range. Dividing their product by 10^14 maintains the
1337  // precision, by scaling the result to 10^16 to 10^18.
1338  //
1339  // If the we're rounding up, we want to round up away
1340  // from zero, and if we're rounding down, truncation
1341  // is implicit.
1342  std::uint64_t amount = muldiv_round(
1343  value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0);
1344 
1345  int offset = offset1 + offset2 + 14;
1346  if (resultNegative != roundUp)
1347  canonicalizeRound(xrp, amount, offset);
1348  STAmount result(issue, amount, offset, resultNegative);
1349 
1350  if (roundUp && !resultNegative && !result)
1351  {
1352  if (xrp)
1353  {
1354  // return the smallest value above zero
1355  amount = 1;
1356  offset = 0;
1357  }
1358  else
1359  {
1360  // return the smallest value above zero
1361  amount = STAmount::cMinValue;
1362  offset = STAmount::cMinOffset;
1363  }
1364  return STAmount(issue, amount, offset, resultNegative);
1365  }
1366  return result;
1367 }
1368 
1369 STAmount
1371  STAmount const& num,
1372  STAmount const& den,
1373  Issue const& issue,
1374  bool roundUp)
1375 {
1376  if (den == beast::zero)
1377  Throw<std::runtime_error>("division by zero");
1378 
1379  if (num == beast::zero)
1380  return {issue};
1381 
1382  std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1383  int numOffset = num.exponent(), denOffset = den.exponent();
1384 
1385  if (num.native())
1386  {
1387  while (numVal < STAmount::cMinValue)
1388  {
1389  numVal *= 10;
1390  --numOffset;
1391  }
1392  }
1393 
1394  if (den.native())
1395  {
1396  while (denVal < STAmount::cMinValue)
1397  {
1398  denVal *= 10;
1399  --denOffset;
1400  }
1401  }
1402 
1403  bool const resultNegative = (num.negative() != den.negative());
1404 
1405  // We divide the two mantissas (each is between 10^15
1406  // and 10^16). To maintain precision, we multiply the
1407  // numerator by 10^17 (the product is in the range of
1408  // 10^32 to 10^33) followed by a division, so the result
1409  // is in the range of 10^16 to 10^15.
1410  //
1411  // We round away from zero if we're rounding up or
1412  // truncate if we're rounding down.
1413  std::uint64_t amount = muldiv_round(
1414  numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1415 
1416  int offset = numOffset - denOffset - 17;
1417 
1418  if (resultNegative != roundUp)
1419  canonicalizeRound(isXRP(issue), amount, offset);
1420 
1421  STAmount result(issue, amount, offset, resultNegative);
1422  if (roundUp && !resultNegative && !result)
1423  {
1424  if (isXRP(issue))
1425  {
1426  // return the smallest value above zero
1427  amount = 1;
1428  offset = 0;
1429  }
1430  else
1431  {
1432  // return the smallest value above zero
1433  amount = STAmount::cMinValue;
1434  offset = STAmount::cMinOffset;
1435  }
1436  return STAmount(issue, amount, offset, resultNegative);
1437  }
1438  return result;
1439 }
1440 
1441 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::STAmount::mIsNative
bool mIsNative
Definition: STAmount.h:56
ripple::STAmount::move
STBase * move(std::size_t n, void *buf) override
Definition: STAmount.cpp:302
ripple::systemCurrencyCode
static std::string const & systemCurrencyCode()
Definition: SystemParameters.h:62
ripple::STAmount::copy
STBase * copy(std::size_t n, void *buf) const override
Definition: STAmount.cpp:296
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::muldiv_round
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
Definition: STAmount.cpp:1121
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1013
ripple::IOUAmount::exponent
int exponent() const noexcept
Definition: IOUAmount.h:163
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::STAmount::cMinValue
static const std::uint64_t cMinValue
Definition: STAmount.h:66
std::exception
STL class.
ripple::STAmount::set
void set(std::int64_t v)
Definition: STAmount.cpp:814
ripple::JsonOptions
JsonOptions
Definition: STBase.h:34
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:327
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:347
ripple::STAmount::mantissa
std::uint64_t mantissa() const noexcept
Definition: STAmount.h:341
std::string::reserve
T reserve(T... args)
ripple::XRPAmount::drops
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:172
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
Json::Value::get
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:834
std::vector< std::string >
std::find_if
T find_if(T... args)
std::string::length
T length(T... args)
ripple::STI_AMOUNT
@ STI_AMOUNT
Definition: SField.h:63
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:550
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:634
ripple::SerializedTypeID
SerializedTypeID
Definition: SField.h:52
ripple::operator-
Number operator-(Number const &x, Number const &y)
Definition: Number.h:277
ripple::STAmount::mValue
mantissa_type mValue
Definition: STAmount.h:54
iterator
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::tenTo14
static const std::uint64_t tenTo14
Definition: STAmount.cpp:39
std::distance
T distance(T... args)
ripple::STAmount::cMinOffset
static const int cMinOffset
Definition: STAmount.h:62
ripple::noIssue
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:103
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
ripple::STAmount::cNotNative
static const std::uint64_t cNotNative
Definition: STAmount.h:72
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
ripple::STAmount::operator=
STAmount & operator=(beast::Zero)
Definition: STAmount.h:388
ripple::Serializer::add64
int add64(std::uint64_t i)
Definition: Serializer.cpp:60
ripple::getSNValue
static std::int64_t getSNValue(STAmount const &amount)
Definition: STAmount.cpp:45
iostream
ripple::STAmount::iou
IOUAmount iou() const
Definition: STAmount.cpp:328
ripple::STAmount::operator-=
STAmount & operator-=(STAmount const &)
Definition: STAmount.cpp:369
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:313
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:161
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1284
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:474
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:86
ripple::STAmount::getFullText
std::string getFullText() const override
Definition: STAmount.cpp:527
ripple::STAmount::exponent
int exponent() const noexcept
Definition: STAmount.h:323
ripple::STAmount::mIssue
Issue mIssue
Definition: STAmount.h:53
ripple::STAmount::setJson
void setJson(Json::Value &) const
Definition: STAmount.cpp:496
ripple::Number
Definition: Number.h:36
ripple::STAmount::STAmount
STAmount(SerialIter &sit, SField const &name)
Definition: STAmount.cpp:67
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::operator+
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:613
ripple::STBase::emplace
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition: STBase.h:165
ripple::SerialIter::get64
std::uint64_t get64()
Definition: Serializer.cpp:399
ripple::operator<
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
Definition: CanonicalTXSet.cpp:25
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1370
ripple::SerialIter::get160
uint160 get160()
Definition: Serializer.h:370
ripple::safe_cast
constexpr std::enable_if_t< std::is_same_v< typename Dest::unit_type, typename Src::unit_type > &&std::is_integral_v< typename Dest::value_type > &&std::is_integral_v< typename Src::value_type >, Dest > safe_cast(Src s) noexcept
Definition: FeeUnits.h:532
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:440
std::to_string
T to_string(T... args)
ripple::muldiv
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
Definition: STAmount.cpp:1100
ripple::STAmount
Definition: STAmount.h:45
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:908
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::SerialIter
Definition: Serializer.h:310
std::uint64_t
ripple::STAmount::setIssue
void setIssue(Issue const &issue)
Set the Issue for this amount and update mIsNative.
Definition: STAmount.cpp:458
ripple::canonicalizeRound
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset)
Definition: STAmount.cpp:1249
ripple::STAmount::construct
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition: STAmount.cpp:290
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:831
ripple::areComparable
static bool areComparable(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:61
memory
std::string::append
T append(T... args)
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::STBase::getFName
SField const & getFName() const
Definition: STBase.cpp:132
ripple::Serializer
Definition: Serializer.h:39
ripple::STAmount::isEquivalent
bool isEquivalent(const STBase &t) const override
Definition: STAmount.cpp:673
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:329
ripple::STAmount::operator+=
STAmount & operator+=(STAmount const &)
Definition: STAmount.cpp:362
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::STAmount::mIsNegative
bool mIsNegative
Definition: STAmount.h:57
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:169
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::amountFromString
STAmount amountFromString(Issue const &issue, std::string const &amount)
Definition: STAmount.cpp:843
ripple::STAmount::isDefault
bool isDefault() const override
Definition: STAmount.cpp:680
ripple::STAmount::unchecked
Definition: STAmount.h:80
ripple::SField
Identifies fields.
Definition: SField.h:112
ripple::STBase
A type which can be exported to a well known binary format.
Definition: STBase.h:66
std::string::begin
T begin(T... args)
std
STL namespace.
ripple::STAmount::canonicalize
void canonicalize()
Definition: STAmount.cpp:704
ripple::STAmount::add
void add(Serializer &s) const override
Definition: STAmount.cpp:642
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::STAmount::negative
bool negative() const noexcept
Definition: STAmount.h:335
std::string::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:95
ripple::STAmount::exponent_type
int exponent_type
Definition: STAmount.h:49
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
std::string::end
T end(T... args)
ripple::STAmount::cMaxNativeN
static const std::uint64_t cMaxNativeN
Definition: STAmount.h:71
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:63
ripple::stNumberSwitchover
LocalValue< bool > stNumberSwitchover(true)
Definition: IOUAmount.h:189
ripple::stAmountCanonicalizeSwitchover
LocalValue< bool > stAmountCanonicalizeSwitchover(true)
Definition: STAmount.h:539
std::make_reverse_iterator
T make_reverse_iterator(T... args)
std::unique_ptr
STL class.
ripple::Number::unchecked
Definition: Number.h:43
ripple::tenTo14m1
static const std::uint64_t tenTo14m1
Definition: STAmount.cpp:40
std::numeric_limits
ripple::STAmount::mOffset
exponent_type mOffset
Definition: STAmount.h:55
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:175
ripple::STAmount::cPosNative
static const std::uint64_t cPosNative
Definition: STAmount.h:73
ripple::STAmount::uRateOne
static const std::uint64_t uRateOne
Definition: STAmount.h:75
ripple::STAmount::getSType
SerializedTypeID getSType() const override
Definition: STAmount.cpp:521
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:67
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:182
ripple::tenTo17
static const std::uint64_t tenTo17
Definition: STAmount.cpp:41
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
beast
Definition: base_uint.h:641