Rename RippleAsset to Issue and RippleBook to Book:

* Split STAmount out of SerializedTypes.h
* New concept of "Issue consistency": when either both or neither of its
  currency and account are XRP.
* Stop checking for consistency of Issue in its constructor.
* Clarification of mIsNative logic in STAmount.
* Usual cleanups.
This commit is contained in:
Tom Ritchford
2014-07-03 18:20:47 -04:00
committed by Nik Bougalis
parent a96dee85d2
commit 206efbf30d
42 changed files with 1611 additions and 1490 deletions

View File

@@ -28,7 +28,7 @@ std::uint64_t STAmount::uRateOne =
std::string STAmount::getHumanCurrency () const
{
return to_string (mCurrency);
return to_string (mIssue.currency);
}
bool STAmount::bSetJson (const Json::Value& jvSource)
@@ -101,14 +101,14 @@ STAmount::STAmount (SField::ref n, const Json::Value& v)
else
{
// non-XRP
if (!to_currency (mCurrency, currency.asString ()))
if (!to_currency (mIssue.currency, currency.asString ()))
throw std::runtime_error ("invalid currency");
if (!issuer.isString ()
|| !to_issuer (mIssuer, issuer.asString ()))
|| !to_issuer (mIssue.account, issuer.asString ()))
throw std::runtime_error ("invalid issuer");
if (mIssuer.isZero ())
if (isXRP (*this))
throw std::runtime_error ("invalid issuer");
}
@@ -157,7 +157,7 @@ STAmount::STAmount (SField::ref n, const Json::Value& v)
bool STAmount::setValue (const std::string& sAmount)
{
// Note: mIsNative and mCurrency must be set already!
// Note: mIsNative and mIssue.currency must be set already!
static boost::regex reNumber (
"\\`([+-]?)(\\d*)(\\.(\\d*))?([eE]([+-]?)(\\d+))?\\'");
@@ -253,14 +253,14 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
//
// Figure out the currency.
//
if (!to_currency (mCurrency, sCurrency))
if (!to_currency (mIssue.currency, sCurrency))
{
WriteLog (lsINFO, STAmount) << "Currency malformed: " << sCurrency;
return false;
}
mIsNative = !mCurrency;
mIsNative = !mIssue.currency;
//
// Figure out the issuer.
@@ -275,10 +275,10 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
return false;
}
mIssuer = naIssuerID.getAccountID ();
mIssue.account = naIssuerID.getAccountID ();
// Stamps not must have an issuer.
if (mIsNative && !mIssuer.isZero ())
if (mIsNative && !isXRP (*this))
{
WriteLog (lsINFO, STAmount) << "Issuer specified for XRP: " << sIssuer;
@@ -289,13 +289,15 @@ bool STAmount::setFullValue (const std::string& sAmount, const std::string& sCur
}
// amount = value * [10 ^ offset]
// representation range is 10^80 - 10^(-80)
// on the wire, high 8 bits are (offset+142), low 56 bits are value
// value is zero if amount is zero, otherwise value is 10^15 to (10^16 - 1) inclusive
// Representation range is 10^80 - 10^(-80).
// On the wire, high 8 bits are (offset+142), low 56 bits are value.
//
// Value is zero if amount is zero, otherwise value is 10^15 to (10^16 - 1)
// inclusive.
void STAmount::canonicalize ()
{
if (mCurrency.isZero ())
if (isXRP (*this))
{
// native currency amounts should always have an offset of zero
mIsNative = true;
@@ -384,8 +386,8 @@ void STAmount::add (Serializer& s) const
else // 256 = positive
s.add64 (mValue | (static_cast<std::uint64_t> (mOffset + 512 + 256 + 97) << (64 - 10)));
s.add160 (mCurrency);
s.add160 (mIssuer);
s.add160 (mIssue.currency);
s.add160 (mIssue.account);
}
}
@@ -398,18 +400,23 @@ STAmount STAmount::createFromInt64 (SField::ref name, std::int64_t value)
void STAmount::setValue (const STAmount& a)
{
mCurrency = a.mCurrency;
mIssuer = a.mIssuer;
mIssue = a.mIssue;
mValue = a.mValue;
mOffset = a.mOffset;
mIsNative = a.mIsNative;
mIsNegative = a.mIsNegative;
}
void STAmount::setIssue (Issue const& issue) {
mIssue = std::move(issue);
mIsNative = isXRP (*this);
}
int STAmount::compare (const STAmount& a) const
{
// Compares the value of a to the value of this STAmount, amounts must be comparable
if (mIsNegative != a.mIsNegative) return mIsNegative ? -1 : 1;
if (mIsNegative != a.mIsNegative)
return mIsNegative ? -1 : 1;
if (!mValue)
{
@@ -446,14 +453,16 @@ STAmount* STAmount::construct (SerializerIterator& sit, SField::ref name)
return new STAmount (name, value, true); // negative
}
Currency currency;
currency.copyFrom (sit.get160 ());
Issue issue;
issue.currency.copyFrom (sit.get160 ());
if (!currency)
throw std::runtime_error ("invalid non-native currency");
if (isXRP (issue.currency))
throw std::runtime_error ("invalid native currency");
Account issuer;
issuer.copyFrom (sit.get160 ());
issue.account.copyFrom (sit.get160 ());
if (isXRP (issue.account))
throw std::runtime_error ("invalid native account");
// 10 bits for the offset, sign and "not native" flag
int offset = static_cast<int> (value >> (64 - 10));
@@ -473,21 +482,23 @@ STAmount* STAmount::construct (SerializerIterator& sit, SField::ref name)
throw std::runtime_error ("invalid currency value");
}
return new STAmount (name, currency, issuer, value, offset, isNegative);
return new STAmount (name, issue, value, offset, isNegative);
}
if (offset != 512)
throw std::runtime_error ("invalid currency value");
return new STAmount (name, currency, issuer);
return new STAmount (name, issue);
}
std::int64_t STAmount::getSNValue () const
{
// signed native value
if (!mIsNative) throw std::runtime_error ("not native");
if (!mIsNative)
throw std::runtime_error ("not native");
if (mIsNegative) return - static_cast<std::int64_t> (mValue);
if (mIsNegative)
return - static_cast<std::int64_t> (mValue);
return static_cast<std::int64_t> (mValue);
}
@@ -526,7 +537,7 @@ std::string STAmount::getText () const
{
ret.append (raw_value);
if(scientific)
if (scientific)
{
ret.append (1, 'e');
ret.append (std::to_string (mOffset));
@@ -604,16 +615,13 @@ bool STAmount::isComparable (const STAmount& t) const
if (t.mIsNative) return false;
return mCurrency == t.mCurrency;
return mIssue.currency == t.mIssue.currency;
}
bool STAmount::isEquivalent (const SerializedType& t) const
{
const STAmount* v = dynamic_cast<const STAmount*> (&t);
if (!v) return false;
return isComparable (*v) && (mIsNegative == v->mIsNegative) && (mValue == v->mValue) && (mOffset == v->mOffset);
return v && (*v == *this);
}
void STAmount::throwComparable (const STAmount& t) const
@@ -625,12 +633,18 @@ void STAmount::throwComparable (const STAmount& t) const
bool STAmount::operator== (const STAmount& a) const
{
return isComparable (a) && (mIsNegative == a.mIsNegative) && (mOffset == a.mOffset) && (mValue == a.mValue);
return isComparable (a) &&
mIsNegative == a.mIsNegative &&
mOffset == a.mOffset &&
mValue == a.mValue;
}
bool STAmount::operator!= (const STAmount& a) const
{
return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable (a);
return mOffset != a.mOffset ||
mValue != a.mValue ||
mIsNegative != a.mIsNegative ||
!isComparable (a);
}
bool STAmount::operator< (const STAmount& a) const
@@ -673,17 +687,19 @@ STAmount STAmount::operator- (void) const
{
if (mValue == 0) return *this;
return STAmount (getFName (), mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative);
return STAmount (
getFName (), mIssue, mValue, mOffset, mIsNative, !mIsNegative);
}
STAmount& STAmount::operator= (std::uint64_t v)
{
// does not copy name, does not change currency type
// Does not copy name, does not change currency type.
mOffset = 0;
mValue = v;
mIsNegative = false;
if (!mIsNative) canonicalize ();
if (!mIsNative)
canonicalize ();
return *this;
}
@@ -732,12 +748,14 @@ bool STAmount::operator>= (std::uint64_t v) const
STAmount STAmount::operator+ (std::uint64_t v) const
{
return STAmount (getFName (), getSNValue () + static_cast<std::int64_t> (v));
return STAmount (
getFName (), getSNValue () + static_cast<std::int64_t> (v));
}
STAmount STAmount::operator- (std::uint64_t v) const
{
return STAmount (getFName (), getSNValue () - static_cast<std::int64_t> (v));
return STAmount (
getFName (), getSNValue () - static_cast<std::int64_t> (v));
}
STAmount::operator double () const
@@ -746,7 +764,8 @@ STAmount::operator double () const
if (!mValue)
return 0.0;
if (mIsNegative) return -1.0 * static_cast<double> (mValue) * pow (10.0, mOffset);
if (mIsNegative)
return -1.0 * static_cast<double> (mValue) * pow (10.0, mOffset);
return static_cast<double> (mValue) * pow (10.0, mOffset);
}
@@ -761,18 +780,22 @@ STAmount operator+ (const STAmount& v1, const STAmount& v2)
if (v1 == zero)
{
// Result must be in terms of v1 currency and issuer.
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue, v2.mOffset, v2.mIsNegative);
return STAmount (v1.getFName (), v1.mIssue,
v2.mValue, v2.mOffset, v2.mIsNegative);
}
if (v1.mIsNative)
return STAmount (v1.getFName (), v1.getSNValue () + v2.getSNValue ());
int ov1 = v1.mOffset, ov2 = v2.mOffset;
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue), vv2 = static_cast<std::int64_t> (v2.mValue);
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue);
std::int64_t vv2 = static_cast<std::int64_t> (v2.mValue);
if (v1.mIsNegative) vv1 = -vv1;
if (v1.mIsNegative)
vv1 = -vv1;
if (v2.mIsNegative) vv2 = -vv2;
if (v2.mIsNegative)
vv2 = -vv2;
while (ov1 < ov2)
{
@@ -786,16 +809,17 @@ STAmount operator+ (const STAmount& v1, const STAmount& v2)
++ov2;
}
// this addition cannot overflow an std::int64_t, it can overflow an STAmount and the constructor will throw
// This addition cannot overflow an std::int64_t. It can overflow an
// STAmount and the constructor will throw.
std::int64_t fv = vv1 + vv2;
if ((fv >= -10) && (fv <= 10))
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
else if (fv >= 0)
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, fv, ov1, false);
return STAmount (v1.getFName (), v1.mIssue);
if (fv >= 0)
return STAmount (v1.getFName (), v1.mIssue, fv, ov1, false);
else
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
return STAmount (v1.getFName (), v1.mIssue, -fv, ov1, true);
}
STAmount operator- (const STAmount& v1, const STAmount& v2)
@@ -807,16 +831,21 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
if (v2.mIsNative)
{
// XXX This could be better, check for overflow and that maximum range is covered.
return STAmount::createFromInt64 (v1.getFName (), v1.getSNValue () - v2.getSNValue ());
// XXX This could be better, check for overflow and that maximum range
// is covered.
return STAmount::createFromInt64 (
v1.getFName (), v1.getSNValue () - v2.getSNValue ());
}
int ov1 = v1.mOffset, ov2 = v2.mOffset;
std::int64_t vv1 = static_cast<std::int64_t> (v1.mValue), vv2 = static_cast<std::int64_t> (v2.mValue);
auto vv1 = static_cast<std::int64_t> (v1.mValue);
auto vv2 = static_cast<std::int64_t> (v2.mValue);
if (v1.mIsNegative) vv1 = -vv1;
if (v1.mIsNegative)
vv1 = -vv1;
if (v2.mIsNegative) vv2 = -vv2;
if (v2.mIsNegative)
vv2 = -vv2;
while (ov1 < ov2)
{
@@ -835,23 +864,22 @@ STAmount operator- (const STAmount& v1, const STAmount& v2)
std::int64_t fv = vv1 - vv2;
if ((fv >= -10) && (fv <= 10))
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
else if (fv >= 0)
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, fv, ov1, false);
return STAmount (v1.getFName (), v1.mIssue);
if (fv >= 0)
return STAmount (v1.getFName (), v1.mIssue, fv, ov1, false);
else
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, -fv, ov1, true);
return STAmount (v1.getFName (), v1.mIssue, -fv, ov1, true);
}
// NIKB TODO Make Amount::divide skip math if den == QUALITY_ONE
STAmount STAmount::divide (
const STAmount& num, const STAmount& den, Currency const& currency,
Account const& issuer)
const STAmount& num, const STAmount& den, Issue const& issue)
{
if (den == zero)
throw std::runtime_error ("division by zero");
if (num == zero)
return STAmount (currency, issuer);
return {issue};
std::uint64_t numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
@@ -884,21 +912,24 @@ STAmount STAmount::divide (
// 10^16 <= quotient <= 10^18
assert (BN_num_bytes (&v) <= 64);
return STAmount (currency, issuer, v.getuint64 () + 5,
numOffset - denOffset - 17, num.mIsNegative != den.mIsNegative);
// TODO(tom): where do 5 and 17 come from?
return STAmount (issue, v.getuint64 () + 5,
numOffset - denOffset - 17,
num.mIsNegative != den.mIsNegative);
}
STAmount STAmount::multiply (
const STAmount& v1, const STAmount& v2, Currency const& currency,
Account const& issuer)
const STAmount& v1, const STAmount& v2, Issue const& issue)
{
if (v1 == zero || v2 == zero)
return STAmount (currency, issuer);
return STAmount (issue);
if (v1.mIsNative && v2.mIsNative && currency.isZero ())
if (v1.mIsNative && v2.mIsNative && isXRP (issue) )
{
std::uint64_t minV = (v1.getSNValue () < v2.getSNValue ()) ? v1.getSNValue () : v2.getSNValue ();
std::uint64_t maxV = (v1.getSNValue () < v2.getSNValue ()) ? v2.getSNValue () : v1.getSNValue ();
std::uint64_t minV = v1.getSNValue () < v2.getSNValue ()
? v1.getSNValue () : v2.getSNValue ();
std::uint64_t maxV = v1.getSNValue () < v2.getSNValue ()
? v2.getSNValue () : v1.getSNValue ();
if (minV > 3000000000ull) // sqrt(cMaxNative)
throw std::runtime_error ("Native value overflow");
@@ -944,8 +975,9 @@ STAmount STAmount::multiply (
// 10^16 <= product <= 10^18
assert (BN_num_bytes (&v) <= 64);
return STAmount (currency, issuer, v.getuint64 () + 7, offset1 + offset2 + 14,
v1.mIsNegative != v2.mIsNegative);
// TODO(tom): where do 7 and 14 come from?
return STAmount (issue, v.getuint64 () + 7,
offset1 + offset2 + 14, v1.mIsNegative != v2.mIsNegative);
}
// Convert an offer into an index amount so they sort by rate.
@@ -964,7 +996,7 @@ std::uint64_t STAmount::getRate (const STAmount& offerOut, const STAmount& offer
try
{
STAmount r = divide (offerIn, offerOut, noCurrency(), noAccount());
STAmount r = divide (offerIn, offerOut, noIssue());
if (r == zero) // offer is too good
return 0;
@@ -985,34 +1017,39 @@ std::uint64_t STAmount::getRate (const STAmount& offerOut, const STAmount& offer
STAmount STAmount::setRate (std::uint64_t rate)
{
if (rate == 0)
return STAmount (noCurrency(), noAccount());
return STAmount (noIssue());
std::uint64_t mantissa = rate & ~ (255ull << (64 - 8));
int exponent = static_cast<int> (rate >> (64 - 8)) - 100;
return STAmount (noCurrency(), noAccount(), mantissa, exponent);
return STAmount (noIssue(), mantissa, exponent);
}
STAmount STAmount::getPay (const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
STAmount STAmount::getPay (
const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed)
{
// Someone wants to get (needed) out of the offer, how much should they pay in?
// Someone wants to get (needed) out of the offer, how much should they pay
// in?
if (offerOut == zero)
return STAmount (offerIn.getCurrency (), offerIn.getIssuer ());
return STAmount (offerIn.issue ());
if (needed >= offerOut)
{
// They need more than offered, pay full amount.
return needed;
}
STAmount ret = divide (multiply (needed, offerIn, noCurrency(), noAccount()), offerOut, offerIn.getCurrency (), offerIn.getIssuer ());
STAmount ret = divide (multiply (needed, offerIn, noIssue()),
offerOut, offerIn.issue());
return (ret > offerIn) ? offerIn : ret;
}
STAmount STAmount::deserialize (SerializerIterator& it)
{
std::unique_ptr<STAmount> s (dynamic_cast<STAmount*> (construct (it, sfGeneric)));
auto s = dynamic_cast<STAmount*> (construct (it, sfGeneric));
if (!s)
throw std::runtime_error("Deserialization error");
STAmount ret (*s);
return ret;
}
@@ -1028,12 +1065,12 @@ std::string STAmount::getFullText () const
{
ret += "/";
if (!mIssuer)
if (isXRP (*this))
ret += "0";
else if (mIssuer == noAccount())
else if (mIssue.account == noAccount())
ret += "1";
else
ret += to_string (mIssuer);
ret += to_string (mIssue.account);
}
return ret;
@@ -1047,9 +1084,9 @@ STAmount STAmount::getRound () const
std::uint64_t valueDigits = mValue % 1000000000ull;
if (valueDigits == 1)
return STAmount (mCurrency, mIssuer, mValue - 1, mOffset, mIsNegative);
return STAmount (mIssue, mValue - 1, mOffset, mIsNegative);
else if (valueDigits == 999999999ull)
return STAmount (mCurrency, mIssuer, mValue + 1, mOffset, mIsNegative);
return STAmount (mIssue, mValue + 1, mOffset, mIsNegative);
return *this;
}
@@ -1083,11 +1120,11 @@ void STAmount::setJson (Json::Value& elem) const
if (!mIsNative)
{
// It is an error for currency or issuer not to be specified for valid json.
// It is an error for currency or issuer not to be specified for valid
// json.
elem[jss::value] = getText ();
elem[jss::currency] = getHumanCurrency ();
elem[jss::issuer] = to_string (mIssuer);
elem[jss::issuer] = to_string (mIssue.account);
}
else
{
@@ -1110,11 +1147,9 @@ public:
static STAmount serializeAndDeserialize (const STAmount& s)
{
Serializer ser;
s.add (ser);
SerializerIterator sit (ser);
return STAmount::deserialize (sit);
}
@@ -1123,17 +1158,17 @@ public:
bool roundTest (int n, int d, int m)
{
// check STAmount rounding
STAmount num (noCurrency(), noAccount(), n);
STAmount den (noCurrency(), noAccount(), d);
STAmount mul (noCurrency(), noAccount(), m);
STAmount quot = STAmount::divide (n, d, noCurrency(), noAccount());
STAmount res = STAmount::multiply (quot, mul, noCurrency(), noAccount());
STAmount num (noIssue(), n);
STAmount den (noIssue(), d);
STAmount mul (noIssue(), m);
STAmount quot = STAmount::divide (n, d, noIssue());
STAmount res = STAmount::multiply (quot, mul, noIssue());
expect (! res.isNative (), "Product should not be native");
res.roundSelf ();
STAmount cmp (noCurrency(), noAccount(), (n * m) / d);
STAmount cmp (noIssue(), (n * m) / d);
expect (! cmp.isNative (), "Comparison amount should not be native");
@@ -1158,13 +1193,13 @@ public:
void mulTest (int a, int b)
{
STAmount aa (noCurrency(), noAccount(), a);
STAmount bb (noCurrency(), noAccount(), b);
STAmount prod1 (STAmount::multiply (aa, bb, noCurrency(), noAccount()));
STAmount aa (noIssue(), a);
STAmount bb (noIssue(), b);
STAmount prod1 (STAmount::multiply (aa, bb, noIssue()));
expect (! prod1.isNative ());
STAmount prod2 (noCurrency(), noAccount(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
STAmount prod2 (noIssue(), static_cast<std::uint64_t> (a) * static_cast<std::uint64_t> (b));
if (prod1 != prod2)
{
@@ -1179,7 +1214,7 @@ public:
}
aa = a;
prod1 = STAmount::multiply (aa, bb, noCurrency(), noAccount());
prod1 = STAmount::multiply (aa, bb, noIssue());
if (prod1 != prod2)
{
@@ -1374,7 +1409,7 @@ public:
{
testcase ("custom currency");
STAmount zeroSt (noCurrency(), noAccount()), one (noCurrency(), noAccount(), 1), hundred (noCurrency(), noAccount(), 100);
STAmount zeroSt (noIssue()), one (noIssue(), 1), hundred (noIssue(), 100);
unexpected (serializeAndDeserialize (zeroSt) != zeroSt, "STAmount fail");
@@ -1500,33 +1535,33 @@ public:
unexpected ((hundred != hundred), "STAmount fail");
unexpected (STAmount (noCurrency(), noAccount()).getText () != "0", "STAmount fail");
unexpected (STAmount (noIssue()).getText () != "0", "STAmount fail");
unexpected (STAmount (noCurrency(), noAccount(), 31).getText () != "31", "STAmount fail");
unexpected (STAmount (noIssue(), 31).getText () != "31", "STAmount fail");
unexpected (STAmount (noCurrency(), noAccount(), 31, 1).getText () != "310", "STAmount fail");
unexpected (STAmount (noIssue(), 31, 1).getText () != "310", "STAmount fail");
unexpected (STAmount (noCurrency(), noAccount(), 31, -1).getText () != "3.1", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -1).getText () != "3.1", "STAmount fail");
unexpected (STAmount (noCurrency(), noAccount(), 31, -2).getText () != "0.31", "STAmount fail");
unexpected (STAmount (noIssue(), 31, -2).getText () != "0.31", "STAmount fail");
unexpected (STAmount::multiply (STAmount (noCurrency(), noAccount(), 20), STAmount (3), noCurrency(), noAccount()).getText () != "60",
unexpected (STAmount::multiply (STAmount (noIssue(), 20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 1");
unexpected (STAmount::multiply (STAmount (noCurrency(), noAccount(), 20), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "60",
unexpected (STAmount::multiply (STAmount (noIssue(), 20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 2");
unexpected (STAmount::multiply (STAmount (20), STAmount (3), noCurrency(), noAccount()).getText () != "60",
unexpected (STAmount::multiply (STAmount (20), STAmount (3), noIssue()).getText () != "60",
"STAmount multiply fail 3");
unexpected (STAmount::multiply (STAmount (20), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "60",
unexpected (STAmount::multiply (STAmount (20), STAmount (3), xrpIssue ()).getText () != "60",
"STAmount multiply fail 4");
if (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (3), noCurrency(), noAccount()).getText () != "20")
if (STAmount::divide (STAmount (noIssue(), 60), STAmount (3), noIssue()).getText () != "20")
{
WriteLog (lsFATAL, STAmount) << "60/3 = " <<
STAmount::divide (STAmount (noCurrency(), noAccount(), 60),
STAmount (3), noCurrency(), noAccount()).getText ();
STAmount::divide (STAmount (noIssue(), 60),
STAmount (3), noIssue()).getText ();
fail ("STAmount divide fail");
}
else
@@ -1534,21 +1569,21 @@ public:
pass ();
}
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (3), xrpCurrency (), xrpIssuer()).getText () != "20",
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (noCurrency(), noAccount(), 3), noCurrency(), noAccount()).getText () != "20",
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), noIssue()).getText () != "20",
"STAmount divide fail");
unexpected (STAmount::divide (STAmount (noCurrency(), noAccount(), 60), STAmount (noCurrency(), noAccount(), 3), xrpCurrency (), xrpIssuer()).getText () != "20",
unexpected (STAmount::divide (STAmount (noIssue(), 60), STAmount (noIssue(), 3), xrpIssue ()).getText () != "20",
"STAmount divide fail");
STAmount a1 (noCurrency(), noAccount(), 60), a2 (noCurrency(), noAccount(), 10, -1);
STAmount a1 (noIssue(), 60), a2 (noIssue(), 10, -1);
unexpected (STAmount::divide (a2, a1, noCurrency(), noAccount()) != STAmount::setRate (STAmount::getRate (a1, a2)),
unexpected (STAmount::divide (a2, a1, noIssue()) != STAmount::setRate (STAmount::getRate (a1, a2)),
"STAmount setRate(getRate) fail");
unexpected (STAmount::divide (a1, a2, noCurrency(), noAccount()) != STAmount::setRate (STAmount::getRate (a2, a1)),
unexpected (STAmount::divide (a1, a2, noIssue()) != STAmount::setRate (STAmount::getRate (a2, a1)),
"STAmount setRate(getRate) fail");
}
@@ -1587,22 +1622,22 @@ public:
unexpected (STAmount::getRate (STAmount (10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 2");
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 1), STAmount (noCurrency(), noAccount(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (noIssue(), 1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 3");
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 10), STAmount (noCurrency(), noAccount(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (noIssue(), 10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 4");
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (noIssue(), 1), STAmount (10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 5");
unexpected (STAmount::getRate (STAmount (noCurrency(), noAccount(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (noIssue(), 10), STAmount (1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 6");
unexpected (STAmount::getRate (STAmount (1), STAmount (noCurrency(), noAccount(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (1), STAmount (noIssue(), 10)) != (((100ull - 14) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 7");
unexpected (STAmount::getRate (STAmount (10), STAmount (noCurrency(), noAccount(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
unexpected (STAmount::getRate (STAmount (10), STAmount (noIssue(), 1)) != (((100ull - 16) << (64 - 8)) | 1000000000000000ull),
"STAmount getRate fail 8");
roundTest (1, 3, 3);
@@ -1637,29 +1672,33 @@ public:
testcase ("underflow");
STAmount bigNative (STAmount::cMaxNative / 2);
STAmount bigValue (noCurrency(), noAccount(),
STAmount bigValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMaxOffset - 1);
STAmount smallValue (noCurrency(), noAccount(),
STAmount smallValue (noIssue(),
(STAmount::cMinValue + STAmount::cMaxValue) / 2, STAmount::cMinOffset + 1);
STAmount zeroSt (noCurrency(), noAccount(), 0);
STAmount zeroSt (noIssue(), 0);
STAmount smallXsmall = STAmount::multiply (smallValue, smallValue, noCurrency(), noAccount());
STAmount smallXsmall = STAmount::multiply (smallValue, smallValue, noIssue());
expect (smallXsmall == zero, "smallXsmall != 0");
STAmount bigDsmall = STAmount::divide (smallValue, bigValue, noCurrency(), noAccount());
STAmount bigDsmall = STAmount::divide (smallValue, bigValue, noIssue());
expect (bigDsmall == zero, beast::String ("small/big != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigNative, noCurrency(), xrpIssuer ());
#if 0
// TODO(tom): this test makes no sense - we should have no way to have
// the currency not be XRP while the account is XRP.
bigDsmall = STAmount::divide (smallValue, bigNative, noCurrency(), xrpAccount ());
#endif
expect (bigDsmall == zero, beast::String ("small/bigNative != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigValue, xrpCurrency (), xrpIssuer ());
bigDsmall = STAmount::divide (smallValue, bigValue, xrpIssue ());
expect (bigDsmall == zero, beast::String ("(small/big)->N != 0: ") + bigDsmall.getText ());
bigDsmall = STAmount::divide (smallValue, bigNative, xrpCurrency (), xrpIssuer ());
bigDsmall = STAmount::divide (smallValue, bigNative, xrpIssue ());
expect (bigDsmall == zero, beast::String ("(small/bigNative)->N != 0: ") + bigDsmall.getText ());
@@ -1688,27 +1727,27 @@ public:
int offset = -14;
STAmount::canonicalizeRound (false, value, offset, true);
STAmount one (noCurrency(), noAccount(), 1);
STAmount two (noCurrency(), noAccount(), 2);
STAmount three (noCurrency(), noAccount(), 3);
STAmount one (noIssue(), 1);
STAmount two (noIssue(), 2);
STAmount three (noIssue(), 3);
STAmount oneThird1 = STAmount::divRound (one, three, noCurrency(), noAccount(), false);
STAmount oneThird2 = STAmount::divide (one, three, noCurrency(), noAccount());
STAmount oneThird3 = STAmount::divRound (one, three, noCurrency(), noAccount(), true);
STAmount oneThird1 = STAmount::divRound (one, three, noIssue(), false);
STAmount oneThird2 = STAmount::divide (one, three, noIssue());
STAmount oneThird3 = STAmount::divRound (one, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << oneThird1;
WriteLog (lsINFO, STAmount) << oneThird2;
WriteLog (lsINFO, STAmount) << oneThird3;
STAmount twoThird1 = STAmount::divRound (two, three, noCurrency(), noAccount(), false);
STAmount twoThird2 = STAmount::divide (two, three, noCurrency(), noAccount());
STAmount twoThird3 = STAmount::divRound (two, three, noCurrency(), noAccount(), true);
STAmount twoThird1 = STAmount::divRound (two, three, noIssue(), false);
STAmount twoThird2 = STAmount::divide (two, three, noIssue());
STAmount twoThird3 = STAmount::divRound (two, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << twoThird1;
WriteLog (lsINFO, STAmount) << twoThird2;
WriteLog (lsINFO, STAmount) << twoThird3;
STAmount oneA = STAmount::mulRound (oneThird1, three, noCurrency(), noAccount(), false);
STAmount oneB = STAmount::multiply (oneThird2, three, noCurrency(), noAccount());
STAmount oneC = STAmount::mulRound (oneThird3, three, noCurrency(), noAccount(), true);
STAmount oneA = STAmount::mulRound (oneThird1, three, noIssue(), false);
STAmount oneB = STAmount::multiply (oneThird2, three, noIssue());
STAmount oneC = STAmount::mulRound (oneThird3, three, noIssue(), true);
WriteLog (lsINFO, STAmount) << oneA;
WriteLog (lsINFO, STAmount) << oneB;
WriteLog (lsINFO, STAmount) << oneC;
@@ -1720,9 +1759,9 @@ public:
WriteLog (lsINFO, STAmount) << fourThirdsB;
WriteLog (lsINFO, STAmount) << fourThirdsC;
STAmount dripTest1 = STAmount::mulRound (twoThird2, two, xrpCurrency (), xrpIssuer (), false);
STAmount dripTest2 = STAmount::multiply (twoThird2, two, xrpCurrency (), xrpIssuer ());
STAmount dripTest3 = STAmount::mulRound (twoThird2, two, xrpCurrency (), xrpIssuer (), true);
STAmount dripTest1 = STAmount::mulRound (twoThird2, two, xrpIssue (), false);
STAmount dripTest2 = STAmount::multiply (twoThird2, two, xrpIssue ());
STAmount dripTest3 = STAmount::mulRound (twoThird2, two, xrpIssue (), true);
WriteLog (lsINFO, STAmount) << dripTest1;
WriteLog (lsINFO, STAmount) << dripTest2;
WriteLog (lsINFO, STAmount) << dripTest3;

View File

@@ -0,0 +1,458 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_STAMOUNT_H
#define RIPPLE_STAMOUNT_H
#include <ripple/module/data/protocol/FieldNames.h>
#include <ripple/module/data/protocol/Serializer.h>
#include <ripple/module/data/protocol/SerializedType.h>
namespace ripple {
// Internal form:
// 1: If amount is zero, then value is zero and offset is -100
// 2: Otherwise:
// legal offset range is -96 to +80 inclusive
// value range is 10^15 to (10^16 - 1) inclusive
// amount = value * [10 ^ offset]
// Wire form:
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
class STAmount : public SerializedType
{
public:
static const int cMinOffset = -96;
static const int cMaxOffset = 80;
static const std::uint64_t cMinValue = 1000000000000000ull;
static const std::uint64_t cMaxValue = 9999999999999999ull;
static const std::uint64_t cMaxNative = 9000000000000000000ull;
// Max native value on network.
static const std::uint64_t cMaxNativeN = 100000000000000000ull;
static const std::uint64_t cNotNative = 0x8000000000000000ull;
static const std::uint64_t cPosNative = 0x4000000000000000ull;
static std::uint64_t uRateOne;
STAmount (std::uint64_t v = 0, bool negative = false)
: mValue (v), mOffset (0), mIsNative (true), mIsNegative (negative)
{
if (v == 0) mIsNegative = false;
}
STAmount (SField::ref n, std::uint64_t v = 0, bool negative = false)
: SerializedType (n), mValue (v), mOffset (0), mIsNative (true),
mIsNegative (negative)
{
}
STAmount (SField::ref n, std::int64_t v)
: SerializedType (n), mOffset (0), mIsNative (true)
{
set (v);
}
STAmount (Issue const& issue,
std::uint64_t uV = 0, int iOff = 0, bool negative = false)
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
{
canonicalize ();
}
STAmount (Issue const& issue,
std::uint32_t uV, int iOff = 0, bool negative = false)
: mIssue(issue), mValue (uV), mOffset (iOff), mIsNegative (negative)
{
canonicalize ();
}
STAmount (SField::ref n, Issue const& issue,
std::uint64_t v = 0, int off = 0, bool negative = false) :
SerializedType (n), mIssue(issue), mValue (v), mOffset (off),
mIsNegative (negative)
{
canonicalize ();
}
STAmount (Issue const& issue, std::int64_t v, int iOff = 0)
: mIssue(issue), mOffset (iOff)
{
set (v);
canonicalize ();
}
STAmount (SField::ref n, Issue const& issue, std::int64_t v, int off = 0)
: SerializedType (n), mIssue(issue), mOffset (off)
{
set (v);
canonicalize ();
}
STAmount (Issue const& issue, int v, int iOff = 0)
: mIssue(issue), mOffset (iOff)
{
set (v);
canonicalize ();
}
STAmount (SField::ref n, Issue const& issue, int v, int off = 0)
: SerializedType (n), mIssue(issue), mOffset (off)
{
set (v);
canonicalize ();
}
STAmount (SField::ref, const Json::Value&);
static STAmount createFromInt64 (SField::ref n, std::int64_t v);
static std::unique_ptr<SerializedType> deserialize (
SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
bool bSetJson (const Json::Value& jvSource);
static STAmount saFromRate (std::uint64_t uRate = 0)
{
return STAmount (noIssue(), uRate, -9, false);
}
SerializedTypeID getSType () const
{
return STI_AMOUNT;
}
std::string getText () const;
std::string getFullText () const;
void add (Serializer& s) const;
int getExponent () const
{
return mOffset;
}
std::uint64_t getMantissa () const
{
return mValue;
}
int signum () const
{
return mValue ? (mIsNegative ? -1 : 1) : 0;
}
// When the currency is XRP, the value in raw units. S=signed
std::uint64_t getNValue () const
{
if (!mIsNative)
throw std::runtime_error ("not native");
return mValue;
}
void setNValue (std::uint64_t v)
{
if (!mIsNative)
throw std::runtime_error ("not native");
mValue = v;
}
std::int64_t getSNValue () const;
void setSNValue (std::int64_t);
std::string getHumanCurrency () const;
bool isNative () const
{
return mIsNative;
}
bool isLegalNet () const
{
return !mIsNative || (mValue <= cMaxNativeN);
}
explicit
operator bool () const noexcept
{
return *this != zero;
}
void negate ()
{
if (*this != zero)
mIsNegative = !mIsNegative;
}
/** @return a copy of amount with the same Issuer and Currency but zero
value. */
STAmount zeroed() const
{
// TODO(tom): what does this next comment mean here?
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
return STAmount (mIssue);
}
void clear ()
{
// VFALCO: Why -100?
mOffset = mIsNative ? 0 : -100;
mValue = 0;
mIsNegative = false;
}
// Zero while copying currency and issuer.
void clear (const STAmount& saTmpl)
{
clear(saTmpl.mIssue);
}
void clear (Issue const& issue)
{
setIssue(issue);
clear ();
}
STAmount& operator=(beast::Zero)
{
clear ();
return *this;
}
int compare (const STAmount&) const;
Account const& getIssuer () const
{
return mIssue.account;
}
void setIssuer (Account const& uIssuer)
{
mIssue.account = uIssuer;
setIssue(mIssue);
}
/** Set the Issue for this amount and update mIsNative. */
void setIssue (Issue const& issue);
Currency const& getCurrency () const
{
return mIssue.currency;
}
Issue const& issue () const
{
return mIssue;
}
bool setValue (const std::string& sAmount);
bool setFullValue (
const std::string& sAmount, const std::string& sCurrency = "",
const std::string& sIssuer = "");
void setValue (const STAmount&);
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{
return (mValue == 0) && mIsNative;
}
bool operator== (const STAmount&) const;
bool operator!= (const STAmount&) const;
bool operator< (const STAmount&) const;
bool operator> (const STAmount&) const;
bool operator<= (const STAmount&) const;
bool operator>= (const STAmount&) const;
bool isComparable (const STAmount&) const;
void throwComparable (const STAmount&) const;
// native currency only
bool operator< (std::uint64_t) const;
bool operator> (std::uint64_t) const;
bool operator<= (std::uint64_t) const;
bool operator>= (std::uint64_t) const;
STAmount operator+ (std::uint64_t) const;
STAmount operator- (std::uint64_t) const;
STAmount operator- (void) const;
STAmount& operator+= (const STAmount&);
STAmount& operator-= (const STAmount&);
STAmount& operator+= (std::uint64_t);
STAmount& operator-= (std::uint64_t);
STAmount& operator= (std::uint64_t);
operator double () const;
friend STAmount operator+ (const STAmount& v1, const STAmount& v2);
friend STAmount operator- (const STAmount& v1, const STAmount& v2);
static STAmount divide (
const STAmount& v1, const STAmount& v2, Issue const& issue);
static STAmount divide (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{
return divide (v1, v2, saUnit.issue ());
}
static STAmount divide (const STAmount& v1, const STAmount& v2)
{
return divide (v1, v2, v1);
}
static STAmount multiply (
const STAmount& v1, const STAmount& v2, Issue const& issue);
static STAmount multiply (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{
return multiply (v1, v2, saUnit.issue());
}
static STAmount multiply (const STAmount& v1, const STAmount& v2)
{
return multiply (v1, v2, v1);
}
/* addRound, subRound can end up rounding if the amount subtracted is too small
to make a change. Consder (X-d) where d is very small relative to X.
If you ask to round down, then (X-d) should not be X unless d is zero.
If you ask to round up, (X+d) should never be X unless d is zero. (Assuming X and d are positive).
*/
// Add, subtract, multiply, or divide rounding result in specified direction
static STAmount addRound (
const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount subRound (
const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount mulRound (
const STAmount& v1, const STAmount& v2, Issue const& issue,
bool roundUp);
static STAmount divRound (
const STAmount& v1, const STAmount& v2, Issue const& issue,
bool roundUp);
static STAmount mulRound (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit,
bool roundUp)
{
return mulRound (v1, v2, saUnit.issue (), roundUp);
}
static STAmount mulRound (
const STAmount& v1, const STAmount& v2, bool roundUp)
{
return mulRound (v1, v2, v1.issue (), roundUp);
}
static STAmount divRound (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit,
bool roundUp)
{
return divRound (v1, v2, saUnit.issue (), roundUp);
}
static STAmount divRound (
const STAmount& v1, const STAmount& v2, bool roundUp)
{
return divRound (v1, v2, v1.issue (), roundUp);
}
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static std::uint64_t getRate (
const STAmount& offerOut, const STAmount& offerIn);
static STAmount setRate (std::uint64_t rate);
// Someone is offering X for Y, I need Z, how much do I pay
// WARNING: most methods in rippled have parameters ordered "in, out" - this
// one is ordered "out, in".
static STAmount getPay (
const STAmount& out, const STAmount& in, const STAmount& needed);
static STAmount deserialize (SerializerIterator&);
Json::Value getJson (int) const;
void setJson (Json::Value&) const;
STAmount getRound () const;
void roundSelf ();
static void canonicalizeRound (
bool isNative, std::uint64_t& value, int& offset, bool roundUp);
private:
Issue mIssue;
std::uint64_t mValue;
int mOffset;
bool mIsNative; // A shorthand for isXRP(mIssue).
bool mIsNegative;
void canonicalize ();
STAmount* duplicate () const
{
return new STAmount (*this);
}
static STAmount* construct (SerializerIterator&, SField::ref name);
STAmount (SField::ref name, Issue const& issue,
std::uint64_t val, int off, bool isNat, bool negative)
: SerializedType (name), mIssue(issue), mValue (val),
mOffset (off), mIsNative (isNat), mIsNegative (negative)
{
}
void set (std::int64_t v)
{
if (v < 0)
{
mIsNegative = true;
mValue = static_cast<std::uint64_t> (-v);
}
else
{
mIsNegative = false;
mValue = static_cast<std::uint64_t> (v);
}
}
void set (int v)
{
if (v < 0)
{
mIsNegative = true;
mValue = static_cast<std::uint64_t> (-v);
}
else
{
mIsNegative = false;
mValue = static_cast<std::uint64_t> (v);
}
}
};
inline bool isXRP(STAmount const& amount)
{
return isXRP (amount.issue().currency);
}
// VFALCO TODO Make static member accessors for these in STAmount
extern const STAmount saZero;
extern const STAmount saOne;
} // ripple
#endif

View File

@@ -73,7 +73,7 @@ STAmount STAmount::addRound (const STAmount& v1, const STAmount& v2, bool roundU
return v1;
if (v1.mValue == 0)
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue,
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
v2.mOffset, v2.mIsNegative);
if (v1.mIsNative)
@@ -122,18 +122,18 @@ STAmount STAmount::addRound (const STAmount& v1, const STAmount& v2, bool roundU
std::int64_t fv = vv1 + vv2;
if ((fv >= -10) && (fv <= 10))
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
return STAmount (v1.getFName (), v1.mIssue);
else if (fv >= 0)
{
std::uint64_t v = static_cast<std::uint64_t> (fv);
canonicalizeRound (false, v, ov1, roundUp);
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, false);
return STAmount (v1.getFName (), v1.mIssue, v, ov1, false);
}
else
{
std::uint64_t v = static_cast<std::uint64_t> (-fv);
canonicalizeRound (false, v, ov1, !roundUp);
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, true);
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
}
}
@@ -145,7 +145,7 @@ STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundU
return v1;
if (v1.mValue == 0)
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v2.mValue,
return STAmount (v1.getFName (), v1.mIssue, v2.mValue,
v2.mOffset, !v2.mIsNegative);
if (v1.mIsNative)
@@ -194,30 +194,29 @@ STAmount STAmount::subRound (const STAmount& v1, const STAmount& v2, bool roundU
std::int64_t fv = vv1 + vv2;
if ((fv >= -10) && (fv <= 10))
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer);
return STAmount (v1.getFName (), v1.mIssue);
if (fv >= 0)
{
std::uint64_t v = static_cast<std::uint64_t> (fv);
canonicalizeRound (false, v, ov1, roundUp);
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, false);
return STAmount (v1.getFName (), v1.mIssue, v, ov1, false);
}
else
{
std::uint64_t v = static_cast<std::uint64_t> (-fv);
canonicalizeRound (false, v, ov1, !roundUp);
return STAmount (v1.getFName (), v1.mCurrency, v1.mIssuer, v, ov1, true);
return STAmount (v1.getFName (), v1.mIssue, v, ov1, true);
}
}
STAmount STAmount::mulRound (
const STAmount& v1, const STAmount& v2, Currency const& currency,
Account const& issuer, bool roundUp)
const STAmount& v1, const STAmount& v2, Issue const& issue, bool roundUp)
{
if (v1 == zero || v2 == zero)
return STAmount (currency, issuer);
return {issue};
if (v1.mIsNative && v2.mIsNative && currency.isZero ())
if (v1.mIsNative && v2.mIsNative && isXRP (issue))
{
std::uint64_t minV = (v1.getSNValue () < v2.getSNValue ()) ?
v1.getSNValue () : v2.getSNValue ();
@@ -274,19 +273,19 @@ STAmount STAmount::mulRound (
std::uint64_t amount = v.getuint64 ();
int offset = offset1 + offset2 + 14;
canonicalizeRound (
currency.isZero (), amount, offset, resultNegative != roundUp);
return STAmount (currency, issuer, amount, offset, resultNegative);
isXRP (issue), amount, offset, resultNegative != roundUp);
return STAmount (issue, amount, offset, resultNegative);
}
STAmount STAmount::divRound (
const STAmount& num, const STAmount& den,
Currency const& currency, Account const& issuer, bool roundUp)
Issue const& issue, bool roundUp)
{
if (den == zero)
throw std::runtime_error ("division by zero");
if (num == zero)
return STAmount (currency, issuer);
return {issue};
std::uint64_t numVal = num.mValue, denVal = den.mValue;
int numOffset = num.mOffset, denOffset = den.mOffset;
@@ -325,8 +324,8 @@ STAmount STAmount::divRound (
std::uint64_t amount = v.getuint64 ();
int offset = numOffset - denOffset - 17;
canonicalizeRound (
currency.isZero (), amount, offset, resultNegative != roundUp);
return STAmount (currency, issuer, amount, offset, resultNegative);
isXRP (issue), amount, offset, resultNegative != roundUp);
return STAmount (issue, amount, offset, resultNegative);
}
} // ripple

View File

@@ -0,0 +1,203 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_SERIALIZEDTYPE_H
#define RIPPLE_SERIALIZEDTYPE_H
#include <ripple/module/data/protocol/FieldNames.h>
#include <ripple/module/data/protocol/Serializer.h>
namespace ripple {
// VFALCO TODO fix this restriction on copy assignment.
//
// CAUTION: Do not create a vector (or similar container) of any object derived
// from SerializedType. Use Boost ptr_* containers. The copy assignment operator
// of SerializedType has semantics that will cause contained types to change
// their names when an object is deleted because copy assignment is used to
// "slide down" the remaining types and this will not copy the field
// name. Changing the copy assignment operator to copy the field name breaks the
// use of copy assignment just to copy values, which is used in the transaction
// engine code.
// VFALCO TODO Remove this unused enum
/*
enum PathFlags
{
PF_END = 0x00, // End of current path & path list.
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
PF_ACCOUNT = 0x01,
PF_OFFER = 0x02,
PF_WANTED_CURRENCY = 0x10,
PF_WANTED_ISSUER = 0x20,
PF_REDEEM = 0x40,
PF_ISSUE = 0x80,
};
*/
//------------------------------------------------------------------------------
/** A type which can be exported to a well known binary format.
A SerializedType:
- Always a field
- Can always go inside an eligible enclosing SerializedType
(such as STArray)
- Has a field name
Like JSON, a SerializedObject is a basket which has rules
on what it can hold.
*/
// VFALCO TODO Document this as it looks like a central class.
// STObject is derived from it
//
class SerializedType
{
public:
SerializedType () : fName (&sfGeneric)
{
;
}
explicit SerializedType (SField::ref n) : fName (&n)
{
assert (fName);
}
virtual ~SerializedType () { }
static std::unique_ptr<SerializedType> deserialize (SField::ref name)
{
return std::unique_ptr<SerializedType> (new SerializedType (name));
}
/** A SerializeType is a field.
This sets the name.
*/
void setFName (SField::ref n)
{
fName = &n;
assert (fName);
}
SField::ref getFName () const
{
return *fName;
}
virtual SerializedTypeID getSType () const
{
return STI_NOTPRESENT;
}
std::unique_ptr<SerializedType> clone () const
{
return std::unique_ptr<SerializedType> (duplicate ());
}
virtual std::string getFullText () const;
virtual std::string getText () const // just the value
{
return std::string ();
}
virtual Json::Value getJson (int /*options*/) const
{
return getText ();
}
virtual void add (Serializer& s) const
{
assert (false);
}
virtual bool isEquivalent (const SerializedType& t) const;
void addFieldID (Serializer& s) const
{
assert (fName->isBinary ());
s.addFieldID (fName->fieldType, fName->fieldValue);
}
SerializedType& operator= (const SerializedType& t);
bool operator== (const SerializedType& t) const
{
return (getSType () == t.getSType ()) && isEquivalent (t);
}
bool operator!= (const SerializedType& t) const
{
return (getSType () != t.getSType ()) || !isEquivalent (t);
}
virtual bool isDefault () const
{
return true;
}
template <class D>
D& downcast()
{
D* ptr = dynamic_cast<D*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
template <class D>
D const& downcast() const
{
D const * ptr = dynamic_cast<D const*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
protected:
// VFALCO TODO make accessors for this
SField::ptr fName;
private:
virtual SerializedType* duplicate () const
{
return new SerializedType (*fName);
}
};
//------------------------------------------------------------------------------
inline SerializedType* new_clone (const SerializedType& s)
{
SerializedType* const copy (s.clone ().release ());
assert (typeid (*copy) == typeid (s));
return copy;
}
inline void delete_clone (const SerializedType* s)
{
boost::checked_delete (s);
}
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
{
return out << t.getFullText ();
}
} // ripple
#endif

View File

@@ -19,8 +19,8 @@
namespace ripple {
const STAmount saZero (noCurrency(), noAccount(), 0);
const STAmount saOne (noCurrency(), noAccount(), 1);
const STAmount saZero (noIssue(), 0);
const STAmount saOne (noIssue(), 1);
SerializedType& SerializedType::operator= (const SerializedType& t)
{
@@ -522,26 +522,6 @@ std::string STPath::getText () const
}
#endif
#if 0
std::string STPathSet::getText () const
{
std::string ret ("{");
bool firstPath = true;
BOOST_FOREACH (std::vector<STPath>::const_iterator::value_type it, value)
{
if (!firstPath)
{
ret += ", ";
firstPath = false;
}
ret += it.getText ();
}
return ret + "}";
}
#endif
void STPathSet::add (Serializer& s) const
{
assert (fName->isBinary ());

View File

@@ -22,183 +22,14 @@
#include <ripple/module/data/protocol/FieldNames.h>
#include <ripple/module/data/protocol/Serializer.h>
#include <ripple/module/data/protocol/SerializedType.h>
#include <ripple/module/data/protocol/STAmount.h>
namespace ripple {
// VFALCO TODO fix this restriction on copy assignment.
//
// CAUTION: Do not create a vector (or similar container) of any object derived
// from SerializedType. Use Boost ptr_* containers. The copy assignment operator
// of SerializedType has semantics that will cause contained types to change
// their names when an object is deleted because copy assignment is used to
// "slide down" the remaining types and this will not copy the field
// name. Changing the copy assignment operator to copy the field name breaks the
// use of copy assignment just to copy values, which is used in the transaction
// engine code.
// VFALCO TODO Remove this unused enum
/*
enum PathFlags
{
PF_END = 0x00, // End of current path & path list.
PF_BOUNDARY = 0xFF, // End of current path & new path follows.
PF_ACCOUNT = 0x01,
PF_OFFER = 0x02,
PF_WANTED_CURRENCY = 0x10,
PF_WANTED_ISSUER = 0x20,
PF_REDEEM = 0x40,
PF_ISSUE = 0x80,
};
*/
//------------------------------------------------------------------------------
/** A type which can be exported to a well known binary format.
A SerializedType:
- Always a field
- Can always go inside an eligible enclosing SerializedType
(such as STArray)
- Has a field name
Like JSON, a SerializedObject is a basket which has rules
on what it can hold.
*/
// VFALCO TODO Document this as it looks like a central class.
// STObject is derived from it
//
class SerializedType
{
public:
SerializedType () : fName (&sfGeneric)
{
;
}
explicit SerializedType (SField::ref n) : fName (&n)
{
assert (fName);
}
virtual ~SerializedType () { }
static std::unique_ptr<SerializedType> deserialize (SField::ref name)
{
return std::unique_ptr<SerializedType> (new SerializedType (name));
}
/** A SerializeType is a field.
This sets the name.
*/
void setFName (SField::ref n)
{
fName = &n;
assert (fName);
}
SField::ref getFName () const
{
return *fName;
}
virtual SerializedTypeID getSType () const
{
return STI_NOTPRESENT;
}
std::unique_ptr<SerializedType> clone () const
{
return std::unique_ptr<SerializedType> (duplicate ());
}
virtual std::string getFullText () const;
virtual std::string getText () const // just the value
{
return std::string ();
}
virtual Json::Value getJson (int /*options*/) const
{
return getText ();
}
virtual void add (Serializer& s) const
{
assert (false);
}
virtual bool isEquivalent (const SerializedType& t) const;
void addFieldID (Serializer& s) const
{
assert (fName->isBinary ());
s.addFieldID (fName->fieldType, fName->fieldValue);
}
SerializedType& operator= (const SerializedType& t);
bool operator== (const SerializedType& t) const
{
return (getSType () == t.getSType ()) && isEquivalent (t);
}
bool operator!= (const SerializedType& t) const
{
return (getSType () != t.getSType ()) || !isEquivalent (t);
}
virtual bool isDefault () const
{
return true;
}
template <class D>
D& downcast()
{
D* ptr = dynamic_cast<D*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
template <class D>
D const& downcast() const
{
D const * ptr = dynamic_cast<D const*> (this);
if (ptr == nullptr)
throw std::runtime_error ("type mismatch");
return *ptr;
}
protected:
// VFALCO TODO make accessors for this
SField::ptr fName;
private:
virtual SerializedType* duplicate () const
{
return new SerializedType (*fName);
}
};
//------------------------------------------------------------------------------
inline SerializedType* new_clone (const SerializedType& s)
{
SerializedType* const copy (s.clone ().release ());
assert (typeid (*copy) == typeid (s));
return copy;
}
inline void delete_clone (const SerializedType* s)
{
boost::checked_delete (s);
}
inline std::ostream& operator<< (std::ostream& out, const SerializedType& t)
{
return out << t.getFullText ();
}
//------------------------------------------------------------------------------
// TODO(tom): make STUInt8, STUInt16, STUInt32, STUInt64 a single templated
// class to reduce the quadruple redundancy we have all over the rippled code
// regarding uint-like types.
class STUInt8 : public SerializedType
{
@@ -443,406 +274,10 @@ private:
//------------------------------------------------------------------------------
// Internal form:
// 1: If amount is zero, then value is zero and offset is -100
// 2: Otherwise:
// legal offset range is -96 to +80 inclusive
// value range is 10^15 to (10^16 - 1) inclusive
// amount = value * [10 ^ offset]
// Wire form:
// High 8 bits are (offset+142), legal range is, 80 to 22 inclusive
// Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive
class STAmount : public SerializedType
{
public:
static const int cMinOffset = -96, cMaxOffset = 80;
static const std::uint64_t cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull;
static const std::uint64_t cMaxNative = 9000000000000000000ull;
static const std::uint64_t cMaxNativeN = 100000000000000000ull; // max native value on network
static const std::uint64_t cNotNative = 0x8000000000000000ull;
static const std::uint64_t cPosNative = 0x4000000000000000ull;
static std::uint64_t uRateOne;
STAmount (std::uint64_t v = 0, bool isNeg = false)
: mValue (v), mOffset (0), mIsNative (true), mIsNegative (isNeg)
{
if (v == 0) mIsNegative = false;
}
STAmount (SField::ref n, std::uint64_t v = 0, bool isNeg = false)
: SerializedType (n), mValue (v), mOffset (0), mIsNative (true), mIsNegative (isNeg)
{
;
}
STAmount (SField::ref n, std::int64_t v) : SerializedType (n), mOffset (0), mIsNative (true)
{
set (v);
}
STAmount (Currency const& currency, Account const& issuer,
std::uint64_t uV = 0, int iOff = 0, bool bNegative = false)
: mCurrency (currency), mIssuer (issuer), mValue (uV), mOffset (iOff), mIsNegative (bNegative)
{
canonicalize ();
}
STAmount (Currency const& currency, Account const& issuer,
std::uint32_t uV, int iOff = 0, bool bNegative = false)
: mCurrency (currency), mIssuer (issuer), mValue (uV), mOffset (iOff), mIsNegative (bNegative)
{
canonicalize ();
}
STAmount (SField::ref n, Currency const& currency, Account const& issuer,
std::uint64_t v = 0, int off = 0, bool isNeg = false) :
SerializedType (n), mCurrency (currency), mIssuer (issuer), mValue (v), mOffset (off), mIsNegative (isNeg)
{
canonicalize ();
}
STAmount (Currency const& currency, Account const& issuer, std::int64_t v, int iOff = 0)
: mCurrency (currency), mIssuer (issuer), mOffset (iOff)
{
set (v);
canonicalize ();
}
STAmount (SField::ref n, Currency const& currency, Account const& issuer, std::int64_t v, int off = 0)
: SerializedType (n), mCurrency (currency), mIssuer (issuer), mOffset (off)
{
set (v);
canonicalize ();
}
STAmount (Currency const& currency, Account const& issuer, int v, int iOff = 0)
: mCurrency (currency), mIssuer (issuer), mOffset (iOff)
{
set (v);
canonicalize ();
}
STAmount (SField::ref n, Currency const& currency, Account const& issuer, int v, int off = 0)
: SerializedType (n), mCurrency (currency), mIssuer (issuer), mOffset (off)
{
set (v);
canonicalize ();
}
STAmount (SField::ref, const Json::Value&);
static STAmount createFromInt64 (SField::ref n, std::int64_t v);
static std::unique_ptr<SerializedType> deserialize (SerializerIterator& sit, SField::ref name)
{
return std::unique_ptr<SerializedType> (construct (sit, name));
}
bool bSetJson (const Json::Value& jvSource);
static STAmount saFromRate (std::uint64_t uRate = 0)
{
return STAmount (noCurrency(), noAccount(), uRate, -9, false);
}
SerializedTypeID getSType () const
{
return STI_AMOUNT;
}
std::string getText () const;
std::string getFullText () const;
void add (Serializer& s) const;
int getExponent () const
{
return mOffset;
}
std::uint64_t getMantissa () const
{
return mValue;
}
int signum () const
{
return mValue ? (mIsNegative ? -1 : 1) : 0;
}
// When the currency is XRP, the value in raw units. S=signed
std::uint64_t getNValue () const
{
if (!mIsNative) throw std::runtime_error ("not native");
return mValue;
}
void setNValue (std::uint64_t v)
{
if (!mIsNative) throw std::runtime_error ("not native");
mValue = v;
}
std::int64_t getSNValue () const;
void setSNValue (std::int64_t);
std::string getHumanCurrency () const;
bool isNative () const
{
return mIsNative;
}
bool isLegalNet () const
{
return !mIsNative || (mValue <= cMaxNativeN);
}
explicit
operator bool () const noexcept
{
return *this != zero;
}
void negate ()
{
if (*this != zero)
mIsNegative = !mIsNegative;
}
// Return a copy of amount with the same Issuer and Currency but zero value.
STAmount zeroed() const
{
STAmount c(mCurrency, mIssuer);
c = zero;
// See https://ripplelabs.atlassian.net/browse/WC-1847?jql=
return c;
}
void clear ()
{
// VFALCO: Why -100?
mOffset = mIsNative ? 0 : -100;
mValue = 0;
mIsNegative = false;
}
// Zero while copying currency and issuer.
void clear (const STAmount& saTmpl)
{
mCurrency = saTmpl.mCurrency;
mIssuer = saTmpl.mIssuer;
mIsNative = saTmpl.mIsNative;
clear ();
}
void clear (Currency const& currency, Account const& issuer)
{
mCurrency = currency;
mIssuer = issuer;
mIsNative = !currency;
clear ();
}
STAmount& operator=(beast::Zero)
{
clear ();
return *this;
}
int compare (const STAmount&) const;
Account const& getIssuer () const
{
return mIssuer;
}
STAmount* setIssuer (Account const& uIssuer)
{
mIssuer = uIssuer;
return this;
}
Currency const& getCurrency () const
{
return mCurrency;
}
bool setValue (const std::string& sAmount);
bool setFullValue (
const std::string& sAmount, const std::string& sCurrency = "",
const std::string& sIssuer = "");
void setValue (const STAmount&);
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{
return (mValue == 0) && mIssuer.isZero () && mCurrency.isZero ();
}
bool operator== (const STAmount&) const;
bool operator!= (const STAmount&) const;
bool operator< (const STAmount&) const;
bool operator> (const STAmount&) const;
bool operator<= (const STAmount&) const;
bool operator>= (const STAmount&) const;
bool isComparable (const STAmount&) const;
void throwComparable (const STAmount&) const;
// native currency only
bool operator< (std::uint64_t) const;
bool operator> (std::uint64_t) const;
bool operator<= (std::uint64_t) const;
bool operator>= (std::uint64_t) const;
STAmount operator+ (std::uint64_t) const;
STAmount operator- (std::uint64_t) const;
STAmount operator- (void) const;
STAmount& operator+= (const STAmount&);
STAmount& operator-= (const STAmount&);
STAmount& operator+= (std::uint64_t);
STAmount& operator-= (std::uint64_t);
STAmount& operator= (std::uint64_t);
operator double () const;
friend STAmount operator+ (const STAmount& v1, const STAmount& v2);
friend STAmount operator- (const STAmount& v1, const STAmount& v2);
static STAmount divide (
const STAmount& v1, const STAmount& v2,
Currency const& currency, Account const& issuer);
static STAmount divide (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{
return divide (v1, v2, saUnit.getCurrency (), saUnit.getIssuer ());
}
static STAmount divide (const STAmount& v1, const STAmount& v2)
{
return divide (v1, v2, v1);
}
static STAmount multiply (
const STAmount& v1, const STAmount& v2,
Currency const& currency, Account const& issuer);
static STAmount multiply (
const STAmount& v1, const STAmount& v2, const STAmount& saUnit)
{
return multiply (v1, v2, saUnit.getCurrency (), saUnit.getIssuer ());
}
static STAmount multiply (const STAmount& v1, const STAmount& v2)
{
return multiply (v1, v2, v1);
}
/* addRound, subRound can end up rounding if the amount subtracted is too small
to make a change. Consder (X-d) where d is very small relative to X.
If you ask to round down, then (X-d) should not be X unless d is zero.
If you ask to round up, (X+d) should never be X unless d is zero. (Assuming X and d are positive).
*/
// Add, subtract, multiply, or divide rounding result in specified direction
static STAmount addRound (const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount subRound (const STAmount& v1, const STAmount& v2, bool roundUp);
static STAmount mulRound (const STAmount& v1, const STAmount& v2,
Currency const& currency, Account const& issuer, bool roundUp);
static STAmount divRound (const STAmount& v1, const STAmount& v2,
Currency const& currency, Account const& issuer, bool roundUp);
static STAmount mulRound (const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
{
return mulRound (v1, v2, saUnit.getCurrency (), saUnit.getIssuer (), roundUp);
}
static STAmount mulRound (const STAmount& v1, const STAmount& v2, bool roundUp)
{
return mulRound (v1, v2, v1.getCurrency (), v1.getIssuer (), roundUp);
}
static STAmount divRound (const STAmount& v1, const STAmount& v2, const STAmount& saUnit, bool roundUp)
{
return divRound (v1, v2, saUnit.getCurrency (), saUnit.getIssuer (), roundUp);
}
static STAmount divRound (const STAmount& v1, const STAmount& v2, bool roundUp)
{
return divRound (v1, v2, v1.getCurrency (), v1.getIssuer (), roundUp);
}
// Someone is offering X for Y, what is the rate?
// Rate: smaller is better, the taker wants the most out: in/out
static std::uint64_t getRate (const STAmount& offerOut, const STAmount& offerIn);
static STAmount setRate (std::uint64_t rate);
// Someone is offering X for Y, I need Z, how much do I pay
static STAmount getPay (
const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed);
static STAmount deserialize (SerializerIterator&);
Json::Value getJson (int) const;
void setJson (Json::Value&) const;
STAmount getRound () const;
void roundSelf ();
static void canonicalizeRound (
bool isNative, std::uint64_t& value, int& offset, bool roundUp);
private:
Currency mCurrency; // Compared by ==. Always update mIsNative.
Account mIssuer; // Not compared by ==. 0 for XRP.
std::uint64_t mValue;
int mOffset;
bool mIsNative; // Always !mCurrency. Native is XRP.
bool mIsNegative;
void canonicalize ();
STAmount* duplicate () const
{
return new STAmount (*this);
}
static STAmount* construct (SerializerIterator&, SField::ref name);
STAmount (SField::ref name, Currency const& cur, Account const& iss,
std::uint64_t val, int off, bool isNat, bool isNeg)
: SerializedType (name), mCurrency (cur), mIssuer (iss), mValue (val),
mOffset (off), mIsNative (isNat), mIsNegative (isNeg)
{
;
}
void set (std::int64_t v)
{
if (v < 0)
{
mIsNegative = true;
mValue = static_cast<std::uint64_t> (-v);
}
else
{
mIsNegative = false;
mValue = static_cast<std::uint64_t> (v);
}
}
void set (int v)
{
if (v < 0)
{
mIsNegative = true;
mValue = static_cast<std::uint64_t> (-v);
}
else
{
mIsNegative = false;
mValue = static_cast<std::uint64_t> (v);
}
}
};
// VFALCO TODO Make static member accessors for these in STAmount
extern const STAmount saZero;
extern const STAmount saOne;
//------------------------------------------------------------------------------
// TODO(tom): make STHash128, STHash160 and STHash256 a single templated class
// to reduce the triple redundancy we have all over the rippled code.
// to reduce the triple redundancy we have all over the rippled code regarding
// hash-like classes.
class STHash128 : public SerializedType
{
public:
@@ -1497,7 +932,6 @@ public:
return true;
}
virtual bool isEquivalent (const SerializedType& t) const;
virtual bool isDefault () const
{